refactor: 推进后端分层架构治理

This commit is contained in:
jxxghp
2026-08-18 00:29:14 +08:00
parent 5d0bacabd5
commit 5128ae9e1e
363 changed files with 34179 additions and 6019 deletions
+75 -397
View File
@@ -1,23 +1,25 @@
import asyncio
import inspect
import random
import threading
import time
import traceback
import uuid
from dataclasses import dataclass
from queue import Empty, PriorityQueue
from typing import Callable, Dict, List, Optional, Tuple, Union, Any, Type
from fastapi.concurrency import run_in_threadpool
from app.runtime.config import global_vars
from app.runtime.thread import ThreadHelper
from app.runtime.log import logger
from app.schemas import ChainEventData
from app.schemas.event import ChainEventData
from app.schemas.types import ChainEventType, EventType
from app.runtime.rate import ExponentialBackoffRateLimiter
from app.foundation.singleton import Singleton
from app.runtime.event.binding import (
EventBindingResolver,
EventHandlerBinding,
HandlerInstanceResolver,
)
from app.runtime.event.dispatch import EventDispatcher
from app.runtime.event.errors import EventErrorNotifier, EventErrorPolicy
from app.runtime.event.registry import EventRegistry
DEFAULT_EVENT_PRIORITY = 10 # 事件的默认优先级
MIN_EVENT_CONSUMER_THREADS = 1 # 最小事件消费者线程数
@@ -25,21 +27,6 @@ INITIAL_EVENT_QUEUE_IDLE_TIMEOUT_SECONDS = 1 # 事件队列空闲时的初始
MAX_EVENT_QUEUE_IDLE_TIMEOUT_SECONDS = 5 # 事件队列空闲时的最大超时时间(秒)
@dataclass(frozen=True, slots=True)
class EventHandlerBinding:
"""描述上层运行时为某个事件处理器提供的实例绑定。"""
instance: Optional[Any]
owner_name: str
run_sync_in_threadpool: bool = False
HandlerInstanceResolver = Callable[
[Type[Any]], Optional[EventHandlerBinding]
]
EventErrorNotifier = Callable[[str, str], object]
class Event:
"""
事件类,封装事件的基本信息
@@ -111,6 +98,32 @@ class EventManager(metaclass=Singleton):
self.__handler_instance_resolvers: Dict[str, HandlerInstanceResolver] = {}
# 由启动组合层注入的错误通知回调
self.__error_notifier: Optional[EventErrorNotifier] = None
self.__registry = EventRegistry(
lock=self.__lock,
broadcast_subscribers=lambda: self.__broadcast_subscribers,
chain_subscribers=lambda: self.__chain_subscribers,
disabled_handlers=lambda: self.__disabled_handlers,
disabled_classes=lambda: self.__disabled_classes,
)
self.__binding_resolver = EventBindingResolver(
lock=self.__lock,
resolvers=lambda: self.__handler_instance_resolvers,
)
self.__error_policy = EventErrorPolicy(
notifier=lambda: self.__error_notifier,
emit_system_error=lambda payload: self.send_event(
EventType.SystemError,
payload,
),
)
self.__dispatcher = EventDispatcher(
registry=self.__registry,
binding_resolver=self.__binding_resolver,
executor=lambda: self.__executor,
event_loop=lambda: global_vars.loop,
event_factory=Event,
error_handler=lambda **kwargs: self.__handle_event_error(**kwargs),
)
def register_handler_instance_resolver(
self,
@@ -122,8 +135,11 @@ class EventManager(metaclass=Singleton):
同名解析器会被替换,避免测试重建单例或热重载后保留旧实例引用。
"""
with self.__lock:
self.__handler_instance_resolvers[name] = resolver
self.__binding_resolver.register(name, resolver)
def unresolved_handler_bindings(self) -> tuple[str, ...]:
"""返回未命中显式 resolver 的类处理器诊断清单。"""
return self.__binding_resolver.unresolved_handlers()
def set_error_notifier(self, notifier: Optional[EventErrorNotifier]) -> None:
"""设置事件处理异常的外部通知回调。"""
@@ -161,18 +177,7 @@ class EventManager(metaclass=Singleton):
:param etype: 事件类型 (EventType 或 ChainEventType)
:return: 返回是否存在可用的处理器
"""
if isinstance(etype, ChainEventType):
handlers = self.__chain_subscribers.get(etype, {})
return any(
self.__is_handler_enabled(handler)
for _, handler in handlers.values()
)
else:
handlers = self.__broadcast_subscribers.get(etype, {})
return any(
self.__is_handler_enabled(handler)
for handler in handlers.values()
)
return self.__registry.check(etype)
def send_event(self, etype: Union[EventType, ChainEventType], data: Optional[Union[Dict, ChainEventData]] = None,
priority: Optional[int] = DEFAULT_EVENT_PRIORITY) -> Optional[Event]:
@@ -219,35 +224,7 @@ class EventManager(metaclass=Singleton):
:param handler: 处理器
:param priority: 可选,链式事件的优先级,默认为 10;广播事件不需要优先级
"""
with self.__lock:
handler_identifier = self.__get_handler_identifier(handler)
if isinstance(event_type, ChainEventType):
# 链式事件,按优先级排序
if event_type not in self.__chain_subscribers:
self.__chain_subscribers[event_type] = {}
handlers = self.__chain_subscribers[event_type]
if handler_identifier in handlers:
handlers.pop(handler_identifier)
else:
logger.debug(
f"Subscribed to chain event: {event_type.value}, "
f"Priority: {priority} - {handler_identifier}")
handlers[handler_identifier] = (priority, handler)
# 根据优先级排序
self.__chain_subscribers[event_type] = dict(
sorted(self.__chain_subscribers[event_type].items(), key=lambda x: x[1][0])
)
else:
# 广播事件
if event_type not in self.__broadcast_subscribers:
self.__broadcast_subscribers[event_type] = {}
handlers = self.__broadcast_subscribers[event_type]
if handler_identifier in handlers:
handlers.pop(handler_identifier)
else:
logger.debug(f"Subscribed to broadcast event: {event_type.value} - {handler_identifier}")
handlers[handler_identifier] = handler
self.__registry.add(event_type, handler, priority or DEFAULT_EVENT_PRIORITY)
def remove_event_listener(self, event_type: Union[EventType, ChainEventType], handler: Callable):
"""
@@ -255,43 +232,21 @@ class EventManager(metaclass=Singleton):
:param event_type: 事件类型 (EventType 或 ChainEventType)
:param handler: 要移除的处理器
"""
with self.__lock:
handler_identifier = self.__get_handler_identifier(handler)
if isinstance(event_type, ChainEventType) and event_type in self.__chain_subscribers:
self.__chain_subscribers[event_type].pop(handler_identifier, None)
logger.debug(f"Unsubscribed from chain event: {event_type.value} - {handler_identifier}")
elif event_type in self.__broadcast_subscribers:
self.__broadcast_subscribers[event_type].pop(handler_identifier, None)
logger.debug(f"Unsubscribed from broadcast event: {event_type.value} - {handler_identifier}")
self.__registry.remove(event_type, handler)
def disable_event_handler(self, target: Union[Callable, type]):
"""
禁用指定的事件处理器或事件处理器类
:param target: 处理器函数或类
"""
identifier = self.__get_handler_identifier(target)
if identifier in self.__disabled_handlers or identifier in self.__disabled_classes:
return
if isinstance(target, type):
self.__disabled_classes.add(identifier)
logger.debug(f"Disabled event handler class - {identifier}")
else:
self.__disabled_handlers.add(identifier)
logger.debug(f"Disabled event handler - {identifier}")
self.__registry.disable(target)
def enable_event_handler(self, target: Union[Callable, type]):
"""
启用指定的事件处理器或事件处理器类
:param target: 处理器函数或类
"""
identifier = self.__get_handler_identifier(target)
if isinstance(target, type):
self.__disabled_classes.discard(identifier)
logger.debug(f"Enabled event handler class - {identifier}")
else:
self.__disabled_handlers.discard(identifier)
logger.debug(f"Enabled event handler - {identifier}")
self.__registry.enable(target)
def visualize_handlers(self) -> List[Dict]:
"""
@@ -299,34 +254,7 @@ class EventManager(metaclass=Singleton):
:return: 处理器列表,包含事件类型、处理器标识符、优先级(如果有)和状态
"""
def parse_handler_data(data):
"""
解析处理器数据,判断是否包含优先级
:param data: 订阅者数据,可能是元组或单一值
:return: (priority, handler),若没有优先级则返回 (None, handler)
"""
if isinstance(data, tuple) and len(data) == 2:
return data
return None, data
handler_info = []
# 统一处理广播事件和链式事件
for event_type, subscribers in {**self.__broadcast_subscribers, **self.__chain_subscribers}.items():
for handler_identifier, handler_data in subscribers.items():
# 解析优先级和处理器
priority, handler = parse_handler_data(handler_data)
# 检查处理器的启用状态
status = "enabled" if self.__is_handler_enabled(handler) else "disabled"
# 构建处理器信息字典
handler_dict = {
"event_type": event_type.value,
"handler_identifier": handler_identifier,
"status": status
}
if priority is not None:
handler_dict["priority"] = priority
handler_info.append(handler_dict)
return handler_info
return self.__registry.visualize()
@classmethod
def __get_handler_identifier(cls, target: Union[Callable, type]) -> Optional[str]:
@@ -335,13 +263,7 @@ class EventManager(metaclass=Singleton):
:param target: 处理器函数或类
:return: 唯一标识符
"""
# 统一使用 inspect.getmodule 来获取模块名
module = inspect.getmodule(target)
module_name = module.__name__ if module else "unknown_module"
# 使用 __qualname__ 获取目标的限定名
qualname = target.__qualname__
return f"{module_name}.{qualname}"
return EventRegistry.handler_identifier(target)
@classmethod
def __get_class_from_callable(cls, handler: Callable) -> Optional[str]:
@@ -350,23 +272,7 @@ class EventManager(metaclass=Singleton):
:param handler: 可调用对象(函数、方法等)
:return: 类的唯一标识符
"""
# 对于绑定方法,通过 __self__.__class__ 获取类
if inspect.ismethod(handler) and hasattr(handler, "__self__"):
return cls.__get_handler_identifier(handler.__self__.__class__)
# 对于类实例(实现了 __call__ 方法)
if not inspect.isfunction(handler) and hasattr(handler, "__call__"):
handler_cls = handler.__class__ # noqa
return cls.__get_handler_identifier(handler_cls)
# 对于未绑定方法、静态方法、类方法,使用 __qualname__ 提取类信息
qualname_parts = handler.__qualname__.split(".")
if len(qualname_parts) > 1:
class_name = ".".join(qualname_parts[:-1])
module = inspect.getmodule(handler)
module_name = module.__name__ if module else "unknown_module"
return f"{module_name}.{class_name}"
return None
return EventRegistry.handler_class_identifier(handler)
def __is_handler_enabled(self, handler: Callable) -> bool:
"""
@@ -374,17 +280,7 @@ class EventManager(metaclass=Singleton):
:param handler: 处理器函数
:return: 如果处理器启用则返回 True,否则返回 False
"""
# 获取处理器的唯一标识符
handler_id = self.__get_handler_identifier(handler)
# 获取处理器所属类的唯一标识符
class_id = self.__get_class_from_callable(handler)
# 检查处理器或类是否被禁用,只要其中之一被禁用则返回 False
if handler_id in self.__disabled_handlers or (class_id is not None and class_id in self.__disabled_classes):
return False
return True
return self.__registry.is_handler_enabled(handler)
def __trigger_chain_event(self, event: Event) -> Optional[Event]:
"""
@@ -415,113 +311,21 @@ class EventManager(metaclass=Singleton):
同步方式调度链式事件,按优先级顺序逐个调用事件处理器,并记录每个处理器的处理时间
:param event: 要调度的事件对象
"""
# 运行期可以动态注册或移除处理器;当前事件始终使用调度开始时的快照。
with self.__lock:
handlers = tuple(
self.__chain_subscribers.get(event.event_type, {}).items()
)
if not handlers:
logger.debug(f"No handlers found for chain event: {event}")
return False
# 过滤出启用的处理器
enabled_handlers = tuple(
(handler_id, priority, handler)
for handler_id, (priority, handler) in handlers
if self.__is_handler_enabled(handler)
)
if not enabled_handlers:
logger.debug(f"No enabled handlers found for chain event: {event}. Skipping execution.")
return False
self.__log_event_lifecycle(event, "Started")
for handler_id, priority, handler in enabled_handlers:
start_time = time.time()
self.__safe_invoke_handler(handler, event)
logger.debug(
f"{self.__get_handler_identifier(handler)} (Priority: {priority}), "
f"completed in {time.time() - start_time:.3f}s for event: {event}"
)
self.__log_event_lifecycle(event, "Completed")
return True
return self.__dispatcher.dispatch_chain(event)
async def __dispatch_chain_event_async(self, event: Event) -> bool:
"""
异步方式调度链式事件,按优先级顺序逐个调用事件处理器,并记录每个处理器的处理时间
:param event: 要调度的事件对象
"""
# 快照在锁内建立、在锁外执行,处理器可以安全地修改后续订阅。
with self.__lock:
handlers = tuple(
self.__chain_subscribers.get(event.event_type, {}).items()
)
if not handlers:
logger.debug(f"No handlers found for chain event: {event}")
return False
# 过滤出启用的处理器
enabled_handlers = tuple(
(handler_id, priority, handler)
for handler_id, (priority, handler) in handlers
if self.__is_handler_enabled(handler)
)
if not enabled_handlers:
logger.debug(f"No enabled handlers found for chain event: {event}. Skipping execution.")
return False
self.__log_event_lifecycle(event, "Started")
for handler_id, priority, handler in enabled_handlers:
start_time = time.time()
await self.__safe_invoke_handler_async(handler, event)
logger.debug(
f"{self.__get_handler_identifier(handler)} (Priority: {priority}), "
f"completed in {time.time() - start_time:.3f}s for event: {event}"
)
self.__log_event_lifecycle(event, "Completed")
return True
return await self.__dispatcher.async_dispatch_chain(event)
def __dispatch_broadcast_event(self, event: Event):
"""
异步方式调度广播事件,通过线程池逐个调用事件处理器
:param event: 要调度的事件对象
"""
# 快照隔离当前调度与运行期订阅变更;变更从下一个事件开始生效。
with self.__lock:
handlers = tuple(
self.__broadcast_subscribers.get(event.event_type, {}).items()
)
if not handlers:
logger.debug(f"No handlers found for broadcast event: {event}")
return
target_plugin_id = None
if event.event_type == EventType.MessageAction and isinstance(event.event_data, dict):
target_plugin_id = event.event_data.get("__mp_target_plugin_id")
# 为每个处理器提供独立的事件实例,防止某个处理器对 event_data 的修改影响其他处理器
for handler_id, handler in handlers:
if target_plugin_id and not self.__should_dispatch_to_target_plugin(
handler, handler_id, str(target_plugin_id)
):
continue
# 仅浅拷贝顶层字典,避免不必要的深拷贝开销;这样可以隔离键级别的替换/赋值
if isinstance(event.event_data, dict):
event_data_copy = event.event_data.copy()
event_data_copy.pop("__mp_target_plugin_id", None)
else:
event_data_copy = event.event_data
isolated_event = Event(event_type=event.event_type,
event_data=event_data_copy,
priority=event.priority)
if inspect.iscoroutinefunction(handler):
# 对于异步函数,直接在事件循环中运行
asyncio.run_coroutine_threadsafe(
self.__safe_invoke_handler_async(handler, isolated_event),
global_vars.loop
)
else:
# 对于同步函数,在线程池中运行
self.__executor.submit(self.__safe_invoke_handler, handler, isolated_event)
self.__dispatcher.dispatch_broadcast(event)
@classmethod
def __should_dispatch_to_target_plugin(
@@ -533,23 +337,11 @@ class EventManager(metaclass=Singleton):
"""
限定插件输入事件只投递给目标插件,避免自由文本被其他插件观察到。
"""
class_name, method_name = cls.__parse_handler_names(handler)
if class_name != target_plugin_id:
return False
identifier_parts = (handler_identifier or "").split(".")
if len(identifier_parts) < 2:
logger.debug(
"Target plugin dispatch skipped because handler identifier is invalid: "
f"target={target_plugin_id}, handler={handler_identifier}"
)
return False
if identifier_parts[-2:] != [class_name, method_name]:
logger.debug(
"Target plugin dispatch skipped because handler identifier does not match handler: "
f"target={target_plugin_id}, handler={handler_identifier}, parsed={class_name}.{method_name}"
)
return False
return True
return EventDispatcher.should_dispatch_to_target_plugin(
handler,
handler_identifier,
target_plugin_id,
)
def __safe_invoke_handler(self, handler: Callable, event: Event):
"""
@@ -557,11 +349,7 @@ class EventManager(metaclass=Singleton):
:param handler: 处理器
:param event: 事件对象
"""
if not self.__is_handler_enabled(handler):
logger.debug(f"Handler {self.__get_handler_identifier(handler)} is disabled. Skipping execution")
return
self.__invoke_handler_by_type_sync(handler, event)
self.__dispatcher.safe_invoke_sync(handler, event)
async def __safe_invoke_handler_async(self, handler: Callable, event: Event):
"""
@@ -569,11 +357,7 @@ class EventManager(metaclass=Singleton):
:param handler: 处理器
:param event: 事件对象
"""
if not self.__is_handler_enabled(handler):
logger.debug(f"Handler {self.__get_handler_identifier(handler)} is disabled. Skipping execution")
return
await self.__invoke_handler_by_type_async(handler, event)
await self.__dispatcher.safe_invoke_async(handler, event)
def __invoke_handler_by_type_sync(self, handler: Callable, event: Event):
"""
@@ -581,20 +365,7 @@ class EventManager(metaclass=Singleton):
:param handler: 处理器
:param event: 要处理的事件对象
"""
resolved = self.__resolve_handler(handler)
if not resolved:
return
method, binding, class_name, method_name = resolved
try:
method(event)
except Exception as e:
self.__handle_event_error(
event=event,
module_name=binding.owner_name,
class_name=class_name,
method_name=method_name,
e=e,
)
self.__dispatcher.invoke_sync(handler, event)
async def __invoke_handler_by_type_async(self, handler: Callable, event: Event):
"""
@@ -602,25 +373,7 @@ class EventManager(metaclass=Singleton):
:param handler: 处理器
:param event: 要处理的事件对象
"""
resolved = self.__resolve_handler(handler)
if not resolved:
return
method, binding, class_name, method_name = resolved
try:
if inspect.iscoroutinefunction(method):
await method(event)
elif binding.run_sync_in_threadpool or not class_name:
await run_in_threadpool(method, event)
else:
method(event)
except Exception as e:
self.__handle_event_error(
event=event,
module_name=binding.owner_name,
class_name=class_name,
method_name=method_name,
e=e,
)
await self.__dispatcher.invoke_async(handler, event)
@staticmethod
def __parse_handler_names(handler: Callable) -> Tuple[str, str]:
@@ -629,82 +382,19 @@ class EventManager(metaclass=Singleton):
:param handler: 处理器
:return: (class_name, method_name)
"""
names = handler.__qualname__.split(".")
if len(names) < 2:
return "", names[0]
return names[0], names[1]
return EventBindingResolver.parse_handler_names(handler)
@staticmethod
def __get_handler_owner_class(handler: Callable) -> Optional[Type[Any]]:
"""从处理器对象本身解析声明它的类,不按命名约定动态导入模块。"""
if inspect.ismethod(handler):
owner = handler.__self__
return owner if isinstance(owner, type) else type(owner)
module = inspect.getmodule(handler)
if not module:
return None
owner: Any = module
for part in handler.__qualname__.split(".")[:-1]:
if part == "<locals>":
return None
owner = getattr(owner, part, None)
if owner is None:
return None
return owner if isinstance(owner, type) else None
return EventBindingResolver.owner_class(handler)
def __resolve_handler(
self,
handler: Callable,
) -> Optional[Tuple[Callable, EventHandlerBinding, str, str]]:
"""将装饰阶段保存的函数解析为当前运行实例上的可调用方法。"""
owner_class = self.__get_handler_owner_class(handler)
method_name = getattr(handler, "__name__", self.__parse_handler_names(handler)[1])
if owner_class is None:
binding = EventHandlerBinding(
instance=None,
owner_name=self.__get_handler_identifier(handler),
run_sync_in_threadpool=True,
)
return handler, binding, "", method_name
with self.__lock:
resolvers = list(self.__handler_instance_resolvers.values())
binding = next(
(result for resolver in resolvers if (result := resolver(owner_class)) is not None),
None,
)
if binding is None:
try:
get_existing = getattr(owner_class, "get_existing_instance", None)
instance = get_existing() if callable(get_existing) else None
if instance is None:
instance = owner_class()
binding = EventHandlerBinding(
instance=instance,
owner_name=owner_class.__name__,
)
except Exception as e:
logger.error(
f"事件处理出错:创建 {owner_class.__name__} 实例失败:"
f"{str(e)} - {traceback.format_exc()}"
)
return None
if binding.instance is None:
return None
method = getattr(binding.instance, method_name, None)
if not callable(method):
# 动态生成的处理器可能只同步了 __qualname____name__ 与类上方法名不一致时
# 回退到限定名末段重试;仍无法解析时记录告警,避免静默跳过
fallback_name = self.__parse_handler_names(handler)[1]
method = getattr(binding.instance, fallback_name, None)
if fallback_name == method_name or not callable(method):
logger.warning(
f"事件处理器 {self.__get_handler_identifier(handler)} "
f"无法解析为实例方法 {owner_class.__name__}.{method_name},跳过执行"
)
return None
method_name = fallback_name
return method, binding, owner_class.__name__, method_name
return self.__binding_resolver.resolve(handler)
def __broadcast_consumer_loop(self):
"""
@@ -737,28 +427,12 @@ class EventManager(metaclass=Singleton):
"""
全局错误处理器,用于处理事件处理中的异常
"""
logger.error(f"{module_name} 事件处理出错:{str(e)} - {traceback.format_exc()}")
# 消息实现由启动组合层注入,事件总线不反向依赖消息模块。
with self.__lock:
notifier = self.__error_notifier
if notifier:
try:
notifier(
f"{module_name} 处理事件 {event.event_type} 时出错",
f"{class_name}.{method_name}{str(e)}",
)
except Exception as notify_error:
logger.error(f"发送事件错误通知失败:{str(notify_error)}")
self.send_event(
EventType.SystemError,
{
"type": "event",
"event_type": event.event_type,
"event_handle": f"{class_name}.{method_name}",
"error": str(e),
"traceback": traceback.format_exc()
}
self.__error_policy.handle(
event=event,
module_name=module_name,
class_name=class_name,
method_name=method_name,
error=e,
)
def register(self, etype: Union[EventType, ChainEventType, List[Union[EventType, ChainEventType]], type],
@@ -797,5 +471,9 @@ class EventManager(metaclass=Singleton):
return decorator
# 全局实例定义
# 模块热重载时类对象会重新创建,但插件和 SDK 可能仍持有旧全局实例。把旧实例登记到
# 新 EventManager 类的单例键,确保所有公开入口继续共享同一个事件总线。
_existing_eventmanager = globals().get("eventmanager")
if _existing_eventmanager is not None:
Singleton._instances[(EventManager, (), frozenset())] = _existing_eventmanager
eventmanager = EventManager()