feat: 装配切换——main/服务构造线/conftest 迁至 Registry(含默认租户过渡兜底)
- main.py: 删全局 engine/async_session;lifespan 装配 TenantRegistry (seed_profiles → 仓库根 tenants/,路径锚定),预热默认租户 jiancai 挂 app.state.default_runtime,逐 active 租户(库文件已存在)跑 sweep_stale_pending,退出 dispose_all。app.state.registry 预置即沿用 (测试注入缝) - routes/runtime.py(过渡,Task 7 删): get_runtime——state.tenant 优先, 缺省落 default_runtime;chat.py/chat_rest.py 全部改走它,消除 main↔routes 循环依赖 - ConversationManager 构造线: 新增 runtime 可选参(持 session_factory/ compiled_wall/config 引用;prompts 仍模块级,Task 6;业务接线 Task 9), fire_pending_pushes 随任务传 session_factory(后台写回派发租户的库) - lead_push_service: 去 app.main import;写库入口显式收 session_factory, 模块级 async_session=None 仅作测试注入兜底 - conftest: client 夹具 = 每测试独立 Registry(tmp data_dir)+ 真实 lifespan 在 TestClient 循环内预热;删 _dispose_main_engine; async_db 保持 NullPool(跨 asyncio.run 循环安全,刻意不换 Registry 引擎) - 测试仅动夹具/桩签名(断言零改动): wiring 桩补 session_factory 形参; history-404 用例改经真实 WS 路由造 widget 会话(引擎常驻连接绑定 TestClient 循环,测试线程不得直开 session_factory) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -17,8 +17,8 @@ from fastapi import APIRouter, HTTPException, Request
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.main import async_session
|
||||
from app.engine.models import ConversationSource, ConversationStatus, Message
|
||||
from app.engine.routes.runtime import get_runtime
|
||||
from app.engine.services.conversation import ConversationManager
|
||||
from app.engine.services.rate_limit import check as rate_check
|
||||
|
||||
@@ -45,8 +45,11 @@ async def chat_session(req: SessionRequest, request: Request):
|
||||
if xf:
|
||||
client_info["ip"] = xf
|
||||
|
||||
async with async_session() as db:
|
||||
manager = ConversationManager(db)
|
||||
# Task 5b: 租户运行时经 state/默认租户兜底解析(过渡期无中间件);
|
||||
# manager 由装配线从 runtime 造(db 会话 + runtime 引用)
|
||||
runtime = get_runtime(request)
|
||||
async with runtime.session_factory() as db:
|
||||
manager = ConversationManager(db, runtime=runtime)
|
||||
if req.session_id:
|
||||
conv = await manager.get_by_session(req.session_id)
|
||||
if conv and conv.status == ConversationStatus.active:
|
||||
@@ -68,12 +71,13 @@ async def chat_session(req: SessionRequest, request: Request):
|
||||
|
||||
|
||||
@router.get("/{session_id}/messages")
|
||||
async def chat_history(session_id: str):
|
||||
async def chat_history(session_id: str, request: Request):
|
||||
"""Public history endpoint for session replay. App-source only, to narrow
|
||||
the read surface; an unknown or non-app session yields 404.
|
||||
"""
|
||||
async with async_session() as db:
|
||||
manager = ConversationManager(db)
|
||||
runtime = get_runtime(request)
|
||||
async with runtime.session_factory() as db:
|
||||
manager = ConversationManager(db, runtime=runtime)
|
||||
conv = await manager.get_by_session(session_id)
|
||||
if not conv or conv.source != ConversationSource.app:
|
||||
raise HTTPException(status_code=404, detail="session not found")
|
||||
@@ -115,8 +119,9 @@ async def chat_message(req: MessageRequest, request: Request):
|
||||
if not rate_check(ip, dev):
|
||||
raise HTTPException(status_code=429, detail="rate limit exceeded")
|
||||
|
||||
async with async_session() as db:
|
||||
manager = ConversationManager(db)
|
||||
runtime = get_runtime(request)
|
||||
async with runtime.session_factory() as db:
|
||||
manager = ConversationManager(db, runtime=runtime)
|
||||
conv = await manager.get_by_session(req.session_id)
|
||||
if not conv:
|
||||
raise HTTPException(status_code=404, detail="session not found")
|
||||
|
||||
Reference in New Issue
Block a user