feat: 增强插件管理和连接稳定性,添加会话令牌重置和组件清理功能
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user