fix: MCP插件TimeoutError修复 + 多项Bug修复和性能优化
- fix: MCP插件管理接口改为后台任务,修复TimeoutError - fix: MCP连接失败后上下文清理的cancel scope错误 - feat: MCP插件后台注册添加重试机制 - fix: 限制每章自动创建伏笔数量上限 - fix: 修复JSON非法转义字符清洗 - fix: SSE流式生成添加心跳保活 - fix: 职业生成改用POST请求避免URL长度限制 - perf: 使用torch CPU版本加速Docker构建 - fix: 自动修复JSON字符串值中的裸换行符 - feat: 集成json5容错解析器
This commit is contained in:
@@ -316,6 +316,9 @@ class MCPClientFacade:
|
||||
if key in self._sessions:
|
||||
await self._close_session_unsafe(key)
|
||||
|
||||
stream_ctx = None
|
||||
session = None
|
||||
|
||||
try:
|
||||
logger.info(f"🔗 连接MCP服务器: {config.plugin_name} -> {config.url} (类型: {config.plugin_type})")
|
||||
|
||||
@@ -365,11 +368,19 @@ class MCPClientFacade:
|
||||
error_details.append(f"{type(exc).__name__}: {exc}")
|
||||
error_msg = "; ".join(error_details)
|
||||
logger.error(f"❌ MCP连接失败 {key}: TaskGroup异常 - {error_msg}")
|
||||
|
||||
# 在同一任务中清理已创建的上下文,避免跨任务清理cancel scope
|
||||
await self._cleanup_contexts_in_task(session, stream_ctx)
|
||||
|
||||
await self._emit_status_change(config.user_id, config.plugin_name, "inactive", "error", error_msg)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ MCP连接失败 {key}: {type(e).__name__}: {e}")
|
||||
|
||||
# 在同一任务中清理已创建的上下文,避免跨任务清理cancel scope
|
||||
await self._cleanup_contexts_in_task(session, stream_ctx)
|
||||
|
||||
await self._emit_status_change(config.user_id, config.plugin_name, "inactive", "error", str(e))
|
||||
return False
|
||||
|
||||
@@ -392,6 +403,27 @@ class MCPClientFacade:
|
||||
|
||||
await self._emit_status_change(user_id, plugin_name, old_status, "inactive", "已注销")
|
||||
|
||||
async def _cleanup_contexts_in_task(self, session, stream_ctx):
|
||||
"""在当前任务中清理已创建的上下文(异步方法)
|
||||
|
||||
当MCP连接失败时,上下文(cancel scope)必须在与创建时相同的任务中清理。
|
||||
由于异常处理和上下文创建在同一个任务中,这里可以安全地await __aexit__。
|
||||
"""
|
||||
# 先清理session,再清理stream(LIFO顺序)
|
||||
if session is not None:
|
||||
try:
|
||||
await session.__aexit__(None, None, None)
|
||||
except Exception as e:
|
||||
logger.debug(f"清理session上下文: {e}")
|
||||
|
||||
if stream_ctx is not None:
|
||||
try:
|
||||
await stream_ctx.__aexit__(None, None, None)
|
||||
except Exception as e:
|
||||
logger.debug(f"清理stream上下文: {e}")
|
||||
|
||||
logger.debug("已在当前任务中清理MCP上下文")
|
||||
|
||||
async def _close_session_unsafe(self, key: str):
|
||||
"""关闭会话(不加用户锁,需要调用者确保线程安全)"""
|
||||
async with self._session_lock:
|
||||
|
||||
Reference in New Issue
Block a user