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:
浅念
2026-10-12 19:15:46 +08:00
parent 0c296ca1ba
commit d041077bb6
11 changed files with 198 additions and 137 deletions
+13
View File
@@ -216,6 +216,19 @@ class TenantRegistry:
"""resolve_site 的便捷形式(双 API 一层实现)。"""
return (await self.resolve_site(host))[0]
# ---- 装配期辅助(Task 5b: main.lifespan 逐租户启动清扫)------------------
def runtimes(self) -> tuple[TenantRuntime, ...]:
"""全部租户运行时的加载期快照(engine 仍懒建)——装配期遍历用
(lifespan 启动清扫逐租户跑)。返回快照 tuple:遍历中 registry_reload
换条目不影响本轮迭代。"""
return tuple(self._by_slug.values())
async def ensure_ready(self, rt: TenantRuntime) -> TenantRuntime:
"""懒建的公开入口(装配期批处理用)——与 resolve 走同一条就绪路径,
现势检查/双检/建库失败半开语义完全一致。"""
return await self._ensure_ready(rt)
# ---- 懒建 / 热加载 / 释放 ---------------------------------------------
async def _ensure_ready(self, rt: TenantRuntime) -> TenantRuntime: