mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 06:56:43 +08:00
refactor: reorganize startup persistence boundaries
This commit is contained in:
@@ -119,7 +119,7 @@ MoviePilot V3 已经完成一轮重要基础工作:原 `app/core`、`app/helpe
|
||||
| 模块 | 静态出度 | 主要原因 |
|
||||
| --- | ---: | --- |
|
||||
| `app.agent.tools.factory` | 99 | 一次性导入全部内置工具并维护集中注册表 |
|
||||
| `app.startup.modules_initializer` | 55 | 组合根职责,这是合理高出度,但仍需声明式管理 |
|
||||
| `app.startup.initializers.modules` | 55 | 组合根职责,这是合理高出度,但仍需声明式管理 |
|
||||
| `app.api.endpoints.system` | 54 | 系统设置、规则测试、日志、网络测试、运行控制混合 |
|
||||
| `app.api.deps` | 49 | 认证、插件配置和跨端点依赖装配集中 |
|
||||
| `app.agent.orchestrator` | 48 | Agent 构建、执行、工具、记忆、审计、用量混合 |
|
||||
@@ -425,7 +425,7 @@ app/chain/transfer.py # 保持 TransferChain 兼容门面
|
||||
|
||||
#### 已有进展
|
||||
|
||||
`app/startup/modules_initializer.py:211-245` 已经承担托管资源、壁纸 Provider、认证载荷、DoH、站点、事件错误通知、模块、Agent 和前端的组合工作。`app/startup/lifecycle.py` 也显式规定数据库预热、路由、模块、插件、调度器、监控器、命令和工作流的顺序。这是正确方向。
|
||||
`app/startup/initializers/modules.py` 承担托管资源、壁纸 Provider、认证载荷、DoH、站点、事件错误通知、模块、Agent 和前端的组合工作。`app/startup/lifecycle/` 显式规定数据库预热、路由、模块、插件、调度器、监控器、命令和工作流的顺序。这是正确方向。
|
||||
|
||||
#### 历史泄漏与当前收口
|
||||
|
||||
@@ -701,7 +701,7 @@ app/application/server/share.py # 订阅/工作流等分享用例
|
||||
|
||||
#### 典型证据
|
||||
|
||||
- `app/application/messaging/skill.py` 通过 `SkillCatalogPort` 消费技能目录,`app.startup.agent_initializer` 才导入并注入 `SkillHelper`。
|
||||
- `app/application/messaging/skill.py` 通过 `SkillCatalogPort` 消费技能目录,`app.startup.initializers.agent` 才导入并注入 `SkillHelper`。
|
||||
- `app/application/plugin/routes.py` 持有 `DynamicRouteRegistry` Protocol 和注册/移除用例;FastAPI app、`app.routes`、`openapi_schema` 和 `setup()` 均封装在 `app/adapters/web/plugin/routes.py`。
|
||||
- 多个 `modules` 直接导入 `app.application.messaging.agent`、`mediaserver`、`storage` 等;其中一部分是合理 SPI 消费,一部分表明应用能力接口和具体实现未区分。
|
||||
- `SystemConfigOper()` 在大量文件中被直接构造,形成持久化配置服务定位器。
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
### 长期整改阶段 0:治理门禁恢复(2026-08-23)
|
||||
|
||||
- 宿主依赖基线已审查 TaskRegistry 与有界后台 owner 接入后的语义差异:当前为 `800` 个模块、`6482` 条内部导入边,12 组重点禁止边继续全部为 `0`,唯一非平凡 SCC 仍是隔离的 TMDB 移植包。
|
||||
- 启动性能探针会在隔离生命周期中真实创建并释放 TaskRegistry;normal/safe 组件数分别为 `20`/`10`,CI 只读检查使用稳定的宿主模块集合和生命周期组件顺序,不再把 Python/平台模块数量当作硬合同。
|
||||
- 宿主依赖基线已审查本阶段归位后的语义差异:当前为 `805` 个模块、`6514` 条内部导入边,12 组重点禁止边继续全部为 `0`,唯一非平凡 SCC 仍是隔离的 TMDB 移植包。
|
||||
- 启动性能探针会在隔离生命周期中真实创建并释放 TaskRegistry;normal/safe 组件数分别为 `23`/`11`,CI 只读检查使用稳定的宿主模块集合和生命周期组件顺序,不再把 Python/平台模块数量当作硬合同。
|
||||
- 官方插件快照覆盖 `plugins.v3`、`plugins.v2` 以及 V3 实际会从 `package.json` 回退加载的 31 个默认实现;`app/plugins/**` 仍只是宿主运行副本,不进入扫描。
|
||||
- SDK 快照以各模块显式 `__all__` 为公开合同,能够记录赋值别名;`typing`、`__future__` 等实现期导入不再被误冻结,既有数据库备份门面已补精确导出清单。
|
||||
- async 阻塞实际债务已由 fixture 中的 10 项下降到 1 项并固化低水位;剩余项是 Scheduler Agent task 查询,后续阶段迁入异步查询边界后归零。
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
- 继续采用单进程控制面是正确选择,不建议现在拆成微服务;插件、调度器、工作流、事件和数据库共享进程内状态,拆分会放大部署、事务和兼容成本。
|
||||
- `foundation/domain/runtime/adapters/application/chain/api/startup` 的职责方向基本成立;宿主架构基线、复杂度 ratchet、异步阻塞 ratchet 当前均通过。
|
||||
- 依赖图当前为 `800` 个 Python 模块、`6479` 条内部导入边;唯一非平凡 SCC 位于隔离的 TMDB 第三方移植包内部,不应为了指标归零重写。
|
||||
- 依赖图当前为 `805` 个 Python 模块、`6514` 条内部导入边;唯一非平凡 SCC 位于隔离的 TMDB 第三方移植包内部,不应为了指标归零重写。
|
||||
- 当前主要风险已经从“目录和依赖失控”转移到运行时协议、后台副作用的可靠性和遗留兼容面。换言之,下一阶段重点应是**语义收口和可验证性**,而不是继续搬文件或机械拆大文件。
|
||||
|
||||
综合评价:架构方向可持续,生产可用性较高;可演进性仍处于中等水平。现阶段没有静态审计发现必须立即推倒重来的 P0 架构问题,但存在需要按 P1/P2 计划治理的真实债务。
|
||||
@@ -82,7 +82,7 @@
|
||||
1. **后台任务的统一所有权已覆盖 API 入口,但仍有更深层任务机制待分级。** `app/runtime/tasks.py` 已建立 lifespan 级 TaskRegistry,启动收尾、插件 Release 刷新、Webhook E0 广播、CookieCloud E1 手工调度、消息入口、Seerr 订阅、整理历史 AI 重做、OpenAI/Anthropic 协议流和 WebAgent 断线后执行/快照保存均不再维护端点模块级任务集合或 Starlette 回调,shutdown 会停止接收、取消并有限等待,且生命周期清单明确登记其顺序。主仓 `app/` 已无裸 FastAPI `BackgroundTasks`;当前仍有约 `50` 个更底层 `create_task`/等价任务创建点,与线程池和 APScheduler 并存,后续需逐项确认 owner、取消、等待、重试、幂等和是否 durable,关键业务副作用优先接入已有 Outbox/恢复表。
|
||||
2. **动态模块契约仍以 legacy 聚合语义为主。** 当前登记 `212` 个模块方法,其中 `194` 个仍使用 `legacy` aggregation,只有 `14` 个 `first_non_empty`、`4` 个 `ordered_list_merge`。`app/runtime/extensions/module/contracts.py:422-455` 已能登记 family、输入/结果标签和基础签名诊断,但 `193` 个方法没有 required parameters,调度器 `app/runtime/extensions/module/dispatcher.py:109-260` 仍主要依赖运行时反射、返回值形状和短路规则。未知第三方方法保留 legacy fallback 是兼容要求,不应删除;宿主高频能力则应逐族补齐可执行的输入校验、结果校验、超时和错误语义。
|
||||
3. **查询侧数据库兼容 ABI 已完成正式装饰器清零。** 写事务装饰器和正式 `db_query/async_db_query` 均为 `0`。站点、消息、用户、订阅、下载/整理历史、工作流、MediaServer、SiteUserData、AgentChat、AgentTaskRun、TransferPending、SystemConfig、PassKey 和 SubscribeHistory 的宿主查询已迁到显式 Session 路径;对应旧插件 Model 调用由独立 `legacy_*` 外壳保留,可同时接受显式 Session 与无 Session 的位置/关键字参数。后续重点转为减少 ORM 对象跨层流转,并保持正式装饰器零回退。
|
||||
4. **组合根和全局状态仍形成复杂的隐式运行时图。** Singleton 实例、模块级 provider、`configure_*` 注册函数和兼容 Facade 同时存在;它们解决了旧 ABI 和启动顺序问题,但增加测试污染、重复装配、实例身份和初始化顺序风险。`app/startup/lifecycle/__init__.py:161-376` 已有声明式生命周期,`app/startup/modules_initializer.py:505-530` 也有分阶段关闭,但尚未做到所有进程级资源都只通过 typed HostRuntime 访问。后续应以“新代码禁止新增 Service Locator/Singleton 依赖、旧入口有命中观测”为 ratchet。
|
||||
4. **组合根和全局状态仍形成复杂的隐式运行时图。** Singleton 实例、模块级 provider、`configure_*` 注册函数和兼容 Facade 同时存在;它们解决了旧 ABI 和启动顺序问题,但增加测试污染、重复装配、实例身份和初始化顺序风险。`app/startup/lifecycle/__init__.py` 已有声明式生命周期,`app/startup/initializers/modules.py` 也有分阶段关闭,但尚未做到所有进程级资源都只通过 typed HostRuntime 访问。后续应以“新代码禁止新增 Service Locator/Singleton 依赖、旧入口有命中观测”为 ratchet。
|
||||
|
||||
### P2:中长期可演进性债务
|
||||
|
||||
@@ -529,7 +529,7 @@ flowchart TB
|
||||
|
||||
**实施记录(2026-08-21)**:
|
||||
|
||||
- `app/startup/subscription.py` 为每次规范新增创建独占同步/异步 Session;
|
||||
- `app/application/subscription/write.py` 定义用例 Port,`app/db/adapters/subscription.py` 为每次规范新增创建独占同步/异步 Session,`app/startup/composition/subscription.py` 只负责注入;
|
||||
`CreateSubscriptionCommand` / `AsyncCreateSubscriptionCommand` 持有 UoW,Oper 只执行
|
||||
查重、`add` 与 `flush`。
|
||||
- `SubscribeOper.stage_add()` 的查重 SQL 已收口到 Oper,不再调用 Model 自动会话装饰器;
|
||||
@@ -584,7 +584,7 @@ flowchart TB
|
||||
**建议结构**:
|
||||
|
||||
```text
|
||||
app/startup/context.py # HostRuntime 及构建结果
|
||||
app/startup/composition/context.py # HostRuntime 及构建结果
|
||||
app/api/context.py # API 可见的最小 AppState / 读取依赖
|
||||
app/api/dependencies/ # 按领域拆分依赖工厂
|
||||
auth.py
|
||||
@@ -612,7 +612,7 @@ app/api/dependencies/ # 按领域拆分依赖工厂
|
||||
|
||||
**实施记录(2026-08-21)**:
|
||||
|
||||
- `app/startup/context.py` 定义 frozen slots `HostRuntime` 与首个窄能力
|
||||
- `app/startup/composition/context.py` 定义 frozen slots `HostRuntime` 与首个窄能力
|
||||
`AgentChatRuntime`,仓储、Session、UoW 字段均为具体 Protocol 工厂,不是字符串字典。
|
||||
- `init_modules()` 保留零参数兼容签名并返回本次 lifespan 唯一 Runtime;生命周期组件把结果挂到
|
||||
`app.state.host_runtime`。`app/api/context.py` 只向 Depends 暴露 Agent chat 的最小能力。
|
||||
@@ -707,7 +707,7 @@ app/api/dependencies/ # 按领域拆分依赖工厂
|
||||
Startup 路径始终使用 HostRuntime 注入。插件 SDK 的 `app.sdk.config.settings`、动态 API 返回和事件字段未改。
|
||||
- 收尾批次把 API 与 Chain 余下直接配置读取全部迁入类型化 snapshot;Scheduler 继续保持为零。
|
||||
`HostRuntime` 新增可变部署设置服务,只供系统设置管理 API 使用,业务 API/Chain 只接收 frozen 字段。
|
||||
snapshot 构造集中到 `app/startup/configuration.py`,生产启动与测试组合根复用同一映射,避免测试默认值
|
||||
snapshot 构造集中到 `app/startup/composition/configuration.py`,生产启动与测试组合根复用同一映射,避免测试默认值
|
||||
漂移。canonical `settings` 直接导入低水位从 154 降到 137,`SystemConfigOper()` 保持 14 个。
|
||||
- `ApiRuntimeConfig` 已覆盖搜索来源、媒体/字幕/音频后缀、重命名格式、WebPush、CookieCloud、根目录和
|
||||
版本标识;`ChainRuntimeConfig` 覆盖搜索、下载、整理、刮削、AI、代理、缓存、链接、路径和 TMDB 图片域。
|
||||
@@ -1080,7 +1080,7 @@ OTel 初始化只能位于 Startup/Adapter;Domain/Application 只依赖 no-op-
|
||||
- 新增 Application command/port
|
||||
- `app/runtime/event/`
|
||||
- `app/runtime/extensions/module/contracts.py`
|
||||
- `app/startup/context.py` / `app/api/context.py`
|
||||
- `app/startup/composition/context.py` / `app/api/context.py`
|
||||
3. 对第三方移植包、旧插件 Facade 和动态 SDK 设置精确豁免,不允许 `app.* = ignore_errors`。
|
||||
4. CI 先检查严格目录;每次迁移扩大 include 范围。
|
||||
5. 类型错误不能用无界 `Any`、`cast(Any, ...)` 或全文件 ignore 消音。
|
||||
@@ -1099,7 +1099,7 @@ OTel 初始化只能位于 Startup/Adapter;Domain/Application 只依赖 no-op-
|
||||
**扩展实施记录(2026-08-22)**:mypy 目标运行时更新到 Python 3.14,严格清单扩大到 20 个源文件;
|
||||
新增纳管配置快照和下载失败事务适配器,仍保持零错误、无全局 ignore。
|
||||
|
||||
Workflow 执行状态 UoW 切片将 `app/application/workflow.py` 与 `app/startup/workflow.py` 纳入 strict 清单,
|
||||
Workflow 执行状态 UoW 切片将 `app/application/workflow.py` 与 `app/db/adapters/workflow.py` 纳入 strict 清单,
|
||||
治理范围扩大到 22 个源文件;事务命令、仓储 Protocol 和短会话适配器保持零错误。
|
||||
|
||||
异步安全与契约收口继续纳管 scheduling facade、Event error policy、Module dispatcher 和 async blocking
|
||||
|
||||
@@ -519,7 +519,7 @@ SYMBOL_ALIASES = {
|
||||
4. Event、模块、插件和安全边界改为由 startup composition root 注入 resolver、回调和错误处理器,迁移模块不再处于强连通分量。
|
||||
5. 插件稳定入口收敛到 `app.sdk`;存量插件无需同步修改,官方插件可以按正常发布节奏迁移。
|
||||
6. 站点二进制和数据资源迁到 `app/application/site`,Build 直接生成 `app.application.site.sites`,Build CI、Resources V3 manifest、Docker 和本地 CLI 使用同一目标路径。
|
||||
7. 媒体识别领域不再直接读取 DB/settings,也不导入 Rust 适配器;`startup/domain_initializer.py` 统一注入实时规则、后缀策略、TMDB 图片地址、默认媒体来源和加速器。
|
||||
7. 媒体识别领域不再直接读取 DB/settings,也不导入 Rust 适配器;`startup/initializers/domain.py` 统一注入实时规则、后缀策略、TMDB 图片地址、默认媒体来源和加速器。
|
||||
8. 缓存按职责拆为 `runtime/cache.py`(契约、内存实现、装饰器、代理)和 `adapters/cache/backends.py`(Redis、文件 I/O);旧 `app.core.cache` 指向完整 `app.sdk.cache` 门面。
|
||||
9. `application/mediaserver.py` 集中负责媒体服务器的配置化服务发现、Provider ID 规范化和音乐库匹配;通用媒体身份规则继续复用 `domain/media.py`。
|
||||
10. GC 归入 `runtime/gc.py`,外部 IP 归属查询归入 `adapters/external/location.py`,安全能力统一在 `app/application/security/`,URL 安全策略为 `url.py`,二次认证文件为 `twofactor.py`。
|
||||
|
||||
Reference in New Issue
Block a user