针对刚才的问题,修改#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
事件中心模块 (最终修正版)
"""
import logging
import threading
import uuid
import time
from enum import Enum
from typing import Dict, List, Callable, Optional, Any, Set, Tuple, DefaultDict
from collections import defaultdict
from dataclasses import dataclass
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
class EventType(Enum):
"""事件类型枚举"""
MODULE_RUN = "module_run"
ANALYSIS_RESULT = "analysis_result"
DATA_UPDATE = "data_update"
ANALYSIS_COMPLETED = "analysis_completed"
CONFIG_SAVED = "config_saved"
DATA_SUBMIT = "data_submit"
INPUT_ANALYSIS = "input_analysis"
COMBINATION_ANALYSIS = "combination_analysis"
TREND_ANALYSIS = "trend_analysis"
NUMBER_GENERATION = "number_generation"
ACK = "ack"
ERROR = "error"
@dataclass
class Event:
"""事件数据类"""
event_id: str
type: str
source: str
target: Optional[str] = None
data: Optional[Dict[str, Any]] = None
token: Optional[str] = None
timestamp: float = time.time()
class EventCenter:
"""线程安全的事件中心单例"""
_instance: Optional['EventCenter'] = None
_lock = threading.Lock()
def __new__(cls) -> 'EventCenter':
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if getattr(self, '_initialized', False):
return
self._lock = threading.RLock()
self._subscribers: DefaultDict[str, List[Tuple[Callable[[Event], None], Optional[str]]]] = defaultdict(list)
self._event_history: Dict[str, Event] = {}
self._pending_acks: Set[str] = set()
self._ack_timeout = 5.0
self._initialized = True
logger.info("EventCenter initialized")
def subscribe(self, event_type: str, handler: Callable[[Event], None], token: Optional[str] = None) -> None:
"""订阅事件"""
if not isinstance(event_type, str):
raise TypeError("event_type must be a string")
if not callable(handler):
raise ValueError("Handler must be callable")
with self._lock:
self._subscribers[event_type].append((handler, token))
logger.debug("Subscribed to %s [token=%s]", event_type, token)
def publish(self, event: Event, require_ack: bool = False) -> bool:
"""发布事件"""
if not isinstance(event, Event):
raise TypeError("Expected Event instance")
with self._lock:
if event.event_id in self._event_history:
logger.warning("Duplicate event %s", event.event_id[:8])
return False
self._event_history[event.event_id] = event
if require_ack:
self._pending_acks.add(event.event_id)
logger.info("Publishing %s event %s", event.type, event.event_id[:8])
handlers: List[Callable[[Event], None]] = []
with self._lock:
for h, t in self._subscribers.get(event.type, []):
if t is None or t == event.token:
handlers.append(h)
if handlers:
threading.Thread(
target=self._dispatch_event,
args=(event, handlers, require_ack),
daemon=True
).start()
return True
def _dispatch_event(self, event: Event, handlers: List[Callable[[Event], None]], require_ack: bool) -> None:
"""分发事件给处理器"""
for handler in handlers:
try:
handler(event)
logger.debug("Event %s handled by %s", event.event_id[:8], handler.__name__)
except Exception as e:
logger.error("Handler failed: %s", str(e), exc_info=True)
self._publish_error(
source="event_center",
target=event.source,
error=e,
context=f"处理{event.type}时出错"
)
if require_ack and event.target:
self._wait_for_ack(event)
def _wait_for_ack(self, event: Event) -> None:
"""等待ACK确认"""
start = time.time()
while time.time() - start < self._ack_timeout:
with self._lock:
if event.event_id not in self._pending_acks:
return
time.sleep(0.1)
logger.warning("ACK timeout for %s", event.event_id[:8])
self._publish_error(
source="event_center",
target=event.source,
error=TimeoutError("ACK timeout"),
context=f"等待{event.target}确认超时"
)
def acknowledge(self, event_id: str) -> None:
"""确认事件处理完成"""
with self._lock:
if event_id in self._pending_acks:
self._pending_acks.remove(event_id)
logger.info("ACK received for %s", event_id[:8])
def _publish_error(self, source: str, target: str, error: Exception, context: str = "") -> None:
"""发布错误事件"""
error_event = Event(
event_id=str(uuid.uuid4()),
type=EventType.ERROR.value,
source=source,
target=target,
data={
"error": str(error),
"context": context,
"timestamp": time.time()
}
)
self.publish(error_event)
# 全局单例实例
event_center = EventCenter()
最新发布