fix(chat): resolve Auto-route failover event-loop freeze (#812)

Root cause: ensure_structured_column() executed a synchronous blocking
engine.connect().execute(SELECT information_schema.columns ...) inside the
async request path (_build_chat_history / _maybe_compress_history), freezing
the uvicorn event loop and hanging all endpoints (~200s, recovered only by
docker restart).

Fix:
- chat_context.py: remove per-request ensure_structured_column() calls; run
  once idempotently at app startup (main.py lifespan). Use CURRENT_DATABASE()
  for PostgreSQL compatibility.
- main.py: add startup-only ensure_structured_column() hook (try/except).
- llm_client.py: trust_env=False + bounded httpx.Timeout/wait_for so broken
  endpoints fail fast instead of hanging the event loop.
- chat_service.py: run media generation in a background daemon thread with its
  own event loop (_launch_media_task_bg) so SSE end does not cancel image/video
  tasks (#811); remove TEMP faulthandler diagnostic.

Safe-align: persist accumulated live container changes (admin/*, knowledge,
market, models, config, observability, mcp_client, platform_knowledge,
im_bot_platform, chat_media, capability_registry, requirements) and add
workflow_templates.

Verified: live failover test (model-006 -> conn-refused) returns in ~1.9s with
concurrent login 0.83s/200; event-loop responsiveness restored (sub-second).
This commit is contained in:
QihuAI Design committed 2026-07-26 00:35:35 +08:00
1 parent 394a7786e0
commit a2504bce34
27 files changed
+253 -59

No files matched your search

+15 -3
View File
@@ -47,6 +47,7 @@ import json
import asyncio
import threading
@@ -7927,7 +7928,7 @@ async def _send_message_core(
asyncio.create_task(
_launch_media_task_bg(ai_msg.id, ai_model.id, req.content, current_user.id)
@@ -7943,7 +7944,6 @@ async def _send_message_core(
_generate_media_task(ai_msg.id, ai_model.id, req.content, current_user.id)
@@ -7959,7 +7959,6 @@ async def _send_message_core(
)
@@ -8547,3 +8546,16 @@ def _check_tool_policy(func_name, mcp_info, skills, policy, call_count, round_co
# 后台线程独立事件循环运行媒体生成,确保 SSE 响应结束后任务不被 uviorn 取消,
# 避免图片/视频永远停留在「生成中…」。_generate_media_task 内部自管 DB 会话。
def _launch_media_task_bg(ai_msg_id, ai_model_id, prompt, user_id):
def _run():
try:
asyncio.run(_generate_media_task(ai_msg_id, ai_model_id, prompt, user_id))
except Exception:
pass
_t = threading.Thread(target=_run, daemon=True)
_t.start()