refactor: 第二轮架构缺陷修复 (1/2/3/4/9/10)

1. 内存泄漏修复:RealtimeChatManager 添加会话自动清理机制
   - 每10次操作检查超时会话(1小时无活动自动清理)
   - 最大活跃会话数限制500,超限清理最旧会话

2. 数据库索引补全:
   - Conversation: session_id, work_order_id 添加索引
   - WorkOrder: status 添加索引
   - ChatSession: user_id 添加索引
   - KnowledgeEntry: category, is_active, is_verified 添加索引

3. ServiceManager 线程安全:
   - 添加 threading.Lock 双重检查锁
   - 防止多线程并发初始化同一服务

4. API 响应格式统一:
   - 新增 api_response() 标准响应函数
   - 统一格式: {success, message, data} / {success, error}

9. asyncio 误用修复:
   - knowledge.py 文件上传改用安全的 asyncio 调用方式
   - 兼容已有事件循环和无事件循环两种场景

10. 请求限流:
    - 新增 rate_limit 装饰器(按 IP 限流)
    - chat/message 限制 20次/分钟
    - workorder/ai-suggestion 限制 5次/分钟
This commit is contained in:
2026-04-02 22:37:44 +08:00
parent 587933f668
commit 7151070c99
11 changed files with 138 additions and 38 deletions

View File

@@ -32,15 +32,49 @@ class ChatMessage:
class RealtimeChatManager:
"""实时对话管理器"""
# 会话超时时间(秒):超过此时间无活动的会话自动清理
SESSION_TIMEOUT = 3600 # 1小时
# 最大同时活跃会话数
MAX_ACTIVE_SESSIONS = 500
def __init__(self):
self.llm_client = QwenClient()
self.knowledge_manager = KnowledgeManager()
self.vehicle_manager = VehicleDataManager()
self.active_sessions = {} # 存储活跃的对话会话
self.message_history = {} # 存储消息历史
self.active_sessions = {}
self.message_history = {}
self._cleanup_counter = 0
def _cleanup_expired_sessions(self):
"""清理超时的会话,每 10 次操作触发一次检查"""
self._cleanup_counter += 1
if self._cleanup_counter < 10:
return
self._cleanup_counter = 0
now = datetime.now()
expired = [
sid for sid, s in self.active_sessions.items()
if (now - s.get("last_activity", now)).total_seconds() > self.SESSION_TIMEOUT
]
for sid in expired:
self.active_sessions.pop(sid, None)
self.message_history.pop(sid, None)
if expired:
logger.info(f"清理了 {len(expired)} 个超时会话,当前活跃: {len(self.active_sessions)}")
# 如果超过上限,清理最旧的
if len(self.active_sessions) > self.MAX_ACTIVE_SESSIONS:
sorted_sessions = sorted(self.active_sessions.items(), key=lambda x: x[1].get("last_activity", datetime.min))
to_remove = len(self.active_sessions) - self.MAX_ACTIVE_SESSIONS
for sid, _ in sorted_sessions[:to_remove]:
self.active_sessions.pop(sid, None)
self.message_history.pop(sid, None)
logger.warning(f"会话数超限,清理了 {to_remove} 个最旧会话")
def create_session(self, user_id: str, work_order_id: Optional[int] = None, tenant_id: Optional[str] = None) -> str:
"""创建新的对话会话"""
self._cleanup_expired_sessions()
session_id = f"session_{user_id}_{int(time.time())}"
session_data = {