P1-1: AIService/AIHandler 真单例 + lifespan close httpx 连接池(修复连接泄漏)

This commit is contained in:
Simon
2026-07-18 00:36:13 +08:00
parent a6518bff03
commit af392f2bf0
+31 -12
View File
@@ -96,14 +96,21 @@ def get_shared_wecom_service():
def get_shared_ai_handler(): def get_shared_ai_handler():
"""获取 AIHandler 共享实例。 """获取 AIHandler 共享实例v4.0 P1-1:真单例)
Returns: Returns:
AIHandler: AI 处理器 AIHandler: AI 处理器
""" """
from app.services.ai_handler import AIHandler global _shared_ai_handler
from app.services.ai_service import AIService if _shared_ai_handler is None:
return AIHandler(ai_service=AIService()) 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 函数(用于路由依赖注入) # FastAPI Depends 函数(用于路由依赖注入)
@@ -134,14 +141,12 @@ def dep_wecom_service():
def dep_ai_handler(): def dep_ai_handler():
"""AIHandler 依赖注入。 """AIHandler 依赖注入v4.0 P1-1:复用同一单例)
Returns: Returns:
AIHandler: AI 处理器 AIHandler: AI 处理器
""" """
from app.services.ai_handler import AIHandler return get_shared_ai_handler()
from app.services.ai_service import AIService
return AIHandler(ai_service=AIService())
def dep_wingman_service(): def dep_wingman_service():
@@ -188,14 +193,28 @@ async def init_shared_services():
async def cleanup_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: if _redis_pool:
await _redis_pool.close() await _redis_pool.close()
_redis_pool = None _redis_pool = None
logger.info("共享服务清理完成") 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 黑名单 Key 前缀(与 auth.py 中保持一致)
TOKEN_BLACKLIST_PREFIX = "token:blacklist:" TOKEN_BLACKLIST_PREFIX = "token:blacklist:"