mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 16:36:53 +08:00
refactor: add transaction ownership ratchet
This commit is contained in:
@@ -342,13 +342,18 @@ SQLAlchemy 查询。`models/` 与 `oper/` 按文件一一镜像(站点族聚
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Caller["Chain / Application / 端点 / Module"]
|
||||
Entry["API / Scheduler / Agent<br/>逻辑操作入口"]
|
||||
Command["Application Command<br/>事务所有者"]
|
||||
UoW["app/db/uow.py<br/>commit / rollback"]
|
||||
Oper["app/db/oper/*.py<br/>SubscribeOper / TransferHistoryOper ..."]
|
||||
Models["app/db/models/*.py<br/>SQLAlchemy 模型"]
|
||||
Engine["app/db/engine.py<br/>同步 + 异步引擎"]
|
||||
DB[("PostgreSQL / SQLite")]
|
||||
|
||||
Caller --> Oper --> Models --> Engine --> DB
|
||||
Entry --> Command --> Oper --> Models --> Engine --> DB
|
||||
Entry --> UoW --> Engine
|
||||
Command -.提交或回滚.-> UoW
|
||||
Command -.commit 后副作用.-> Effects["Event / Scheduler / Report"]
|
||||
Models -.before_insert/before_update.-> Norm["_identity.py<br/>media_source/media_id 归一化"]
|
||||
```
|
||||
|
||||
@@ -356,6 +361,9 @@ flowchart LR
|
||||
归 `app/application/`(见 `application/subscription/write.py`、`application/history.py`)。
|
||||
订阅新增、查询、变更、删除、身份和搜索契约已经统一收口在 `application/subscription/`,
|
||||
不再保留主题包之外的第二个写入入口。
|
||||
- Oper 只 stage mutation,不创建独立 Session、不提交;Application Command 通过请求或任务
|
||||
入口注入的 UnitOfWork 统一 `commit/rollback`,事件、刷新和上报只在 commit 成功后执行。
|
||||
`transaction-debt-baseline.json` 将存量 178 个 Model 事务装饰器冻结为只降不增低水位。
|
||||
- 每次表结构变更必须新增 `database/versions/` 下的 Alembic 迁移。
|
||||
- 运行期业务配置使用 `SystemConfigKey` 枚举 + `SystemConfigOper`,禁止裸字符串键;
|
||||
用户级配置使用 `UserConfigOper`。
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
> 审计范围:宿主后端;排除 `app/plugins/**` 运行时插件副本
|
||||
> 规范优先级:`AGENTS.md` 与 `docs/rules/` 高于本文
|
||||
> 相关文档:`docs/architecture-overview.md`、`docs/refactor/backend-architecture-governance.md`、`docs/refactor/backend-module-refactor-compatibility.md`
|
||||
> 实施进度:阶段 0(ARCH-201~203)与阶段 1(ARCH-210~212)已完成,后续任务按 ID 独立提交和回滚
|
||||
> 实施进度:阶段 0(ARCH-201~203)、阶段 1(ARCH-210~212)与 ARCH-220 已完成,后续任务按 ID 独立提交和回滚
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
|
||||
@@ -81,6 +81,29 @@ the stub.
|
||||
Oper classes accept and return persistence values. Turning a `MediaInfo` or
|
||||
`MetaBase` into a row is business logic and lives in `app/application/`.
|
||||
|
||||
### Transaction ownership ratchet
|
||||
|
||||
- `tests/fixtures/architecture/transaction-debt-baseline.json` records the
|
||||
existing Model transaction decorators. The current 178 legacy decorators are
|
||||
migration debt: they may decrease but must never increase or move to a new
|
||||
Model method.
|
||||
- New Model methods must not use `db_query`, `db_update`, `async_db_query`, or
|
||||
`async_db_update`, create a Session, or call `commit()` / `rollback()`.
|
||||
- Oper receives a caller-owned Session and may query, add, update, delete, or
|
||||
flush. A composable Oper method must not create its own Session and must not
|
||||
commit or roll back.
|
||||
- The API, Scheduler, Agent, or another logical operation entry creates the
|
||||
Session and adapts it through `app/db/uow.py`. Application command code owns
|
||||
`commit()` / `rollback()`; events, scheduling refresh, reports, and other
|
||||
external effects run only after a successful commit.
|
||||
- A synchronous Session is private to one worker thread. An AsyncSession is
|
||||
private to one asyncio task/operation; neither may be stored in a process
|
||||
singleton or reused by concurrent work.
|
||||
|
||||
Run `./.venv/bin/python scripts/architecture/baseline.py --check-host` after
|
||||
persistence changes. A deliberate debt reduction may refresh the low-water mark
|
||||
with `--write-host`; never refresh it to accept newly introduced debt.
|
||||
|
||||
**Standard Oper method conventions:**
|
||||
|
||||
```python
|
||||
|
||||
Reference in New Issue
Block a user