feat: 增强插件管理和连接稳定性,添加会话令牌重置和组件清理功能

This commit is contained in:
DrSmoothl
2026-03-12 22:51:14 +08:00
parent 793dee08d4
commit 688b53ee24
8 changed files with 137 additions and 15 deletions

View File

@@ -93,6 +93,14 @@ class ComponentRegistry:
comp = RegisteredComponent(name, component_type, plugin_id, metadata)
if comp.full_name in self._components:
logger.warning(f"组件 {comp.full_name} 已存在,覆盖")
# 从 _by_plugin 列表中移除旧条目,防止幽灵组件堆积
old_comp = self._components[comp.full_name]
old_list = self._by_plugin.get(old_comp.plugin_id)
if old_list is not None:
try:
old_list.remove(old_comp)
except ValueError:
pass
self._components[comp.full_name] = comp

View File

@@ -73,6 +73,11 @@ class RPCServer:
def session_token(self) -> str:
return self._session_token
def reset_session_token(self) -> str:
"""重新生成会话令牌(热重载时调用,防止旧 Runner 重连)"""
self._session_token = secrets.token_hex(32)
return self._session_token
@property
def runner_generation(self) -> int:
return self._runner_generation
@@ -155,7 +160,7 @@ class RPCServer:
raise RPCError(ErrorCode.E_BACKPRESSURE, "发送队列已满")
# 注册 pending future
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
future: asyncio.Future[Envelope] = loop.create_future()
self._pending_requests[request_id] = future
@@ -227,6 +232,11 @@ class RPCServer:
if self._connection is conn:
self._connection = None
self._runner_id = None
# 连接断开时,立即让所有等待中的请求失败,避免挂起至超时
for req_id, future in list(self._pending_requests.items()):
if not future.done():
future.set_exception(RPCError(ErrorCode.E_PLUGIN_CRASHED, "Runner 连接已断开"))
self._pending_requests.clear()
async def _handle_handshake(self, conn: Connection) -> bool:
"""处理 runner.hello 握手"""
@@ -369,7 +379,12 @@ class RPCServer:
"""处理来自 Runner 的事件"""
if handler := self._method_handlers.get(envelope.method):
try:
await handler(envelope)
result = await handler(envelope)
# 检查 handler 返回的信封是否包含错误信息
if result is not None and isinstance(result, Envelope) and result.error:
logger.warning(
f"事件 {envelope.method} handler 返回错误: {result.error.get('message', '')}"
)
except Exception as e:
logger.error(f"处理事件 {envelope.method} 异常: {e}", exc_info=True)

View File

@@ -222,9 +222,19 @@ class PluginSupervisor:
# 启动 RPC Server
await self._rpc_server.start()
# 计算预期 generation与 reload_plugins 保持一致)
expected_generation = self._rpc_server.runner_generation + 1
# 拉起 Runner 进程
await self._spawn_runner()
# 等待 Runner 完成连接,避免 start() 返回时 Runner 尚未就绪
try:
await self._wait_for_runner_generation(expected_generation, timeout_sec=30.0)
except TimeoutError:
if not self._rpc_server.is_connected:
logger.warning("Runner 未在 30s 内完成连接,后续操作可能失败")
# 启动健康检查
self._health_task = asyncio.create_task(self._health_check_loop())
@@ -283,6 +293,9 @@ class PluginSupervisor:
old_registered_plugins = dict(self._registered_plugins)
expected_generation = self._rpc_server.runner_generation + 1
# 重新生成 session token防止被终止的旧 Runner 重连
self._rpc_server.reset_session_token()
# 清理旧的组件注册,防止幽灵组件残留
self._clear_runtime_state()