Files
wecom_it_smart_desk/docs/11-历史归档/deploy-nas-archived-20260704/backend/app/dependencies.py
T

249 lines
8.4 KiB
Python

# =============================================================================
# 企微智能IT支持服务台 — FastAPI 依赖注入 & 共享服务管理
# =============================================================================
# 说明:集中管理 Redis、AIService、WecomService、AIHandler 等共享服务实例,
# 解决原代码中多处手动创建/关闭服务导致的资源泄漏问题。
#
# 提供:
# 1. 应用级共享实例的初始化和清理(在 main.py 的 lifespan 中调用)
# 2. FastAPI Depends 依赖注入函数(供 h5.py 等路由模块使用)
# 3. 模块级访问函数(供 wecom_callback.py 等非 DI 场景使用)
#
# 资源管理原则:
# - 共享实例在应用启动时创建一次,关闭时清理一次
# - 路由端点通过 Depends 获取共享实例,不再手动创建/关闭
# - httpx.AsyncClient 连接池由共享 AIService 和 WecomService 复用
# =============================================================================
import logging
from typing import Optional
import redis.asyncio as aioredis
from fastapi import Depends
from app.config import settings
from app.services.ai_service import AIService
from app.services.ai_handler import AIHandler
from app.services.wecom_service import WecomService
from app.services.wingman_service import WingmanService
logger = logging.getLogger(__name__)
# --------------------------------------------------------------------------
# 全局共享实例(由 init_shared_services / cleanup_shared_services 管理)
# --------------------------------------------------------------------------
_redis_client: Optional[aioredis.Redis] = None
_ai_service: Optional[AIService] = None
_wecom_service: Optional[WecomService] = None
_ai_handler: Optional[AIHandler] = None
_wingman_service: Optional[WingmanService] = None
# --------------------------------------------------------------------------
# 应用生命周期管理(在 main.py 的 lifespan 中调用)
# --------------------------------------------------------------------------
async def init_shared_services() -> None:
"""初始化共享服务实例(在应用启动时调用)。
创建 Redis 客户端、AIService、WecomService、AIHandler 的全局共享实例。
所有实例在应用运行期间复用,避免每次请求重新创建导致资源泄漏。
如果 Redis 不可用,会记录警告但不阻塞启动(降级运行)。
"""
global _redis_client, _ai_service, _wecom_service, _ai_handler, _wingman_service
# 1. 初始化 Redis 客户端(可能不可用,容错处理)
try:
_redis_client = aioredis.from_url(settings.redis_url)
await _redis_client.ping()
logger.info("共享 Redis 客户端初始化成功")
except Exception as e:
logger.warning(f"共享 Redis 客户端初始化失败(降级运行): {e}")
_redis_client = None
# 2. 初始化 AI 服务(共享 httpx 连接池)
_ai_service = AIService()
logger.info("共享 AIService 初始化成功")
# 3. 初始化企微服务(使用共享 Redis)
_wecom_service = WecomService(_redis_client)
logger.info("共享 WecomService 初始化成功")
# 4. 初始化 AI 处理器(统一 AI 调用逻辑)
_ai_handler = AIHandler(_ai_service)
logger.info("共享 AIHandler 初始化成功")
# 5. 初始化 Wingman 服务(坐席智能副驾驶,独立 Agent)
_wingman_service = WingmanService()
logger.info("共享 WingmanService 初始化成功")
async def cleanup_shared_services() -> None:
"""清理共享服务实例(在应用关闭时调用)。
按照依赖关系逆序关闭:AIHandler → WecomService → AIService → Redis。
确保所有 httpx 连接池和 Redis 连接被正确释放。
"""
global _redis_client, _ai_service, _wecom_service, _ai_handler, _wingman_service
# AIHandler 无需关闭(无外部资源)
_ai_handler = None
if _wecom_service:
try:
await _wecom_service.close()
except Exception as e:
logger.warning(f"WecomService 关闭异常: {e}")
_wecom_service = None
if _ai_service:
try:
await _ai_service.close()
except Exception as e:
logger.warning(f"AIService 关闭异常: {e}")
_ai_service = None
if _wingman_service:
try:
await _wingman_service.close()
except Exception as e:
logger.warning(f"WingmanService 关闭异常: {e}")
_wingman_service = None
if _redis_client:
try:
await _redis_client.close()
except Exception as e:
logger.warning(f"Redis 客户端关闭异常: {e}")
_redis_client = None
logger.info("共享服务实例清理完成")
# --------------------------------------------------------------------------
# 模块级访问函数(供 wecom_callback.py 等非 DI 场景使用)
# --------------------------------------------------------------------------
def get_shared_redis() -> Optional[aioredis.Redis]:
"""获取共享 Redis 客户端(非 DI 方式)。
适用于无法使用 FastAPI Depends 的场景(如回调处理器)。
Returns:
Optional[aioredis.Redis]: Redis 客户端实例,不可用时为 None
"""
return _redis_client
def get_shared_ai_service() -> Optional[AIService]:
"""获取共享 AI 服务(非 DI 方式)。
Returns:
Optional[AIService]: AI 服务实例,不可用时为 None
"""
return _ai_service
def get_shared_wecom_service() -> Optional[WecomService]:
"""获取共享企微服务(非 DI 方式)。
Returns:
Optional[WecomService]: 企微服务实例,不可用时为 None
"""
return _wecom_service
def get_shared_ai_handler() -> Optional[AIHandler]:
"""获取共享 AI 处理器(非 DI 方式)。
Returns:
Optional[AIHandler]: AI 处理器实例,不可用时为 None
"""
return _ai_handler
def get_shared_wingman_service() -> Optional[WingmanService]:
"""获取共享 Wingman 服务(非 DI 方式)。
Returns:
Optional[WingmanService]: Wingman 服务实例,不可用时为 None
"""
return _wingman_service
# --------------------------------------------------------------------------
# FastAPI 依赖注入函数(供路由端点使用)
# --------------------------------------------------------------------------
async def dep_redis() -> Optional[aioredis.Redis]:
"""获取共享 Redis 客户端(FastAPI 依赖注入)。
Redis 不可用时返回 None,调用方根据业务需要决定是否降级处理。
Returns:
Optional[aioredis.Redis]: Redis 客户端实例
"""
return _redis_client
async def dep_ai_service() -> AIService:
"""获取共享 AI 服务(FastAPI 依赖注入)。
AI 服务不可用时抛出异常(AI 为核心功能,不可降级)。
Returns:
AIService: AI 服务实例
Raises:
RuntimeError: AI 服务未初始化
"""
if _ai_service is None:
raise RuntimeError("AI 服务未初始化,请检查应用启动日志")
return _ai_service
async def dep_wecom_service() -> WecomService:
"""获取共享企微服务(FastAPI 依赖注入)。
企微服务不可用时抛出异常(核心通信功能,不可降级)。
Returns:
WecomService: 企微服务实例
Raises:
RuntimeError: 企微服务未初始化
"""
if _wecom_service is None:
raise RuntimeError("企微服务未初始化,请检查应用启动日志")
return _wecom_service
async def dep_ai_handler() -> AIHandler:
"""获取共享 AI 处理器(FastAPI 依赖注入)。
AI 处理器不可用时抛出异常(核心功能,不可降级)。
Returns:
AIHandler: AI 处理器实例
Raises:
RuntimeError: AI 处理器未初始化
"""
if _ai_handler is None:
raise RuntimeError("AI 处理器未初始化,请检查应用启动日志")
return _ai_handler
async def dep_wingman_service() -> WingmanService:
"""获取共享 Wingman 服务(FastAPI 依赖注入)。
Wingman 服务不可用时抛出异常。
Returns:
WingmanService: Wingman 服务实例
Raises:
RuntimeError: Wingman 服务未初始化
"""
if _wingman_service is None:
raise RuntimeError("Wingman 服务未初始化,请检查应用启动日志")
return _wingman_service