diff --git a/backend/app/dependencies/__init__.py b/backend/app/dependencies/__init__.py index 45312c3..f6f53b8 100644 --- a/backend/app/dependencies/__init__.py +++ b/backend/app/dependencies/__init__.py @@ -96,14 +96,21 @@ def get_shared_wecom_service(): def get_shared_ai_handler(): - """获取 AIHandler 共享实例。 + """获取 AIHandler 共享实例(v4.0 P1-1:真单例)。 Returns: - AIHandler: AI 处理器实例 + AIHandler: AI 处理器单例 """ - from app.services.ai_handler import AIHandler - from app.services.ai_service import AIService - return AIHandler(ai_service=AIService()) + global _shared_ai_handler + if _shared_ai_handler is None: + from app.services.ai_handler import AIHandler + from app.services.ai_service import AIService + _shared_ai_handler = AIHandler(ai_service=AIService()) + return _shared_ai_handler + + +# v4.0 P1-1: AIHandler 模块级单例(修复每次新建导致的 httpx 连接池泄漏) +_shared_ai_handler = None # FastAPI Depends 函数(用于路由依赖注入) @@ -134,14 +141,12 @@ def dep_wecom_service(): def dep_ai_handler(): - """AIHandler 依赖注入。 + """AIHandler 依赖注入(v4.0 P1-1:复用同一单例)。 Returns: - AIHandler: AI 处理器实例 + AIHandler: AI 处理器单例 """ - from app.services.ai_handler import AIHandler - from app.services.ai_service import AIService - return AIHandler(ai_service=AIService()) + return get_shared_ai_handler() def dep_wingman_service(): @@ -188,14 +193,28 @@ async def init_shared_services(): async def cleanup_shared_services(): """清理共享服务(应用关闭时调用)。 - 关闭 Redis 连接池。 + 关闭 Redis 连接池 + AIService httpx 连接池(v4.0 P1-1)。 """ - global _redis_pool + global _redis_pool, _shared_ai_handler if _redis_pool: await _redis_pool.close() _redis_pool = None logger.info("共享服务清理完成") + # v4.0 P1-1: 关闭 AIService 的 2 个 httpx 连接池(修复 Unclosed client session) + if _shared_ai_handler is not None: + try: + ai_service = getattr(_shared_ai_handler, 'ai_service', None) + if ai_service: + for client_attr in ('_client', '_native_client'): + client = getattr(ai_service, client_attr, None) + if client and not client.is_closed: + await client.aclose() + logger.info("AIService httpx 连接池已关闭") + except Exception as e: + logger.warning(f"AIService 连接池关闭异常: {e}") + _shared_ai_handler = None + # Token 黑名单 Key 前缀(与 auth.py 中保持一致) TOKEN_BLACKLIST_PREFIX = "token:blacklist:"