P1-1: AIService/AIHandler 真单例 + lifespan close httpx 连接池(修复连接泄漏)
This commit is contained in:
@@ -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:"
|
||||
|
||||
Reference in New Issue
Block a user