108 lines
4.4 KiB
Markdown
108 lines
4.4 KiB
Markdown
# database_fastapi 修改意见
|
||
|
||
> 针对文件:`E:\project\yh_one\new_project\yuhengyihao_client\yxd\app_fastapi\database_fastapi.py`
|
||
> 背景:需要与线上主库强一致;断网可记日志,恢复后合并回放至线上;主写在线上。
|
||
> 对照能力:宇信达智建平台 `dbsync` 出站队列 / 冲突 / 对账(见 `ai建站/docs/数据同步-中间件.md`)。
|
||
|
||
---
|
||
|
||
## 落地状态(已实现)
|
||
|
||
| 项 | 状态 | 位置 |
|
||
|----|------|------|
|
||
| 统一写网关 `apply_write` | ✅ | `db_write_gateway.py` |
|
||
| 写接口收口 | ✅ | insert / update / update/id / delete / sql(DML) |
|
||
| 库绑定防串库 | ✅ | `sync_binding.py` → `cache/db_bindings/bindings.json` |
|
||
| 配置 | ✅ | `sync_config.py`(环境变量) |
|
||
| 断网 pending | ✅ | 复用 `QueueDatabaseManager`,库名默认 `sync_pending` |
|
||
| 手动回放 | ✅ | `POST /database/sync/replay` |
|
||
| 绑定/状态 API | ✅ | `/database/sync/*` |
|
||
| 后台自动回放 | ✅ 可选 | `sync_replay_worker.py`,需 `YXD_SYNC_REPLAY_WORKER=1` |
|
||
| DDL / 批量 import 收口 | ⏳ 未做 | 仍可直写本地;后续按需收口 |
|
||
| 冲突队列 API | ⏳ 未做 | 回放失败即停保序,暂无独立 conflicts 列表 |
|
||
|
||
**默认安全**:`YXD_SYNC_MODE` 未配且无 `YXD_ONLINE_API_BASE` 时为 **`local_only`**(只写本地,仍会 ensure 绑定信息)。
|
||
配了 `YXD_ONLINE_API_BASE` 且未显式写 `YXD_SYNC_MODE` 时自动升为 **`online_primary`**。
|
||
|
||
### 环境变量
|
||
|
||
| 变量 | 说明 | 默认 |
|
||
|------|------|------|
|
||
| `YXD_SYNC_MODE` | `local_only` \| `online_primary` | `local_only`(有 ONLINE_BASE 且未设 mode 则升 primary) |
|
||
| `YXD_ONLINE_API_BASE` | 线上 API 根,如 `https://api.example.com` | 空 |
|
||
| `YXD_ONLINE_TIMEOUT_SEC` | 线上写超时 | `8` |
|
||
| `YXD_OFFLINE_POLICY` | `pending_log` \| `reject` | `pending_log` |
|
||
| `YXD_SYNC_ENFORCE_BINDING` | 是否强制已绑定 | `true` |
|
||
| `YXD_SYNC_AUTO_ENSURE_BINDING` | 写时自动 ensure | `true` |
|
||
| `YXD_SYNC_PENDING_QUEUE` | pending 队列库名 | `sync_pending` |
|
||
| `YXD_ONLINE_TOKEN_HEADER` | 透传 token 头 | `Authorization` |
|
||
| `YXD_SYNC_REPLAY_WORKER` | 启后台回放 | 关 |
|
||
| `YXD_SYNC_REPLAY_INTERVAL_SEC` | 回放间隔秒 | `30` |
|
||
|
||
### 新增/改动文件
|
||
|
||
```text
|
||
yxd/app_fastapi/
|
||
db_write_gateway.py # apply_write / replay_pending
|
||
sync_config.py
|
||
sync_binding.py
|
||
sync_context.py # Request → WriteContext
|
||
sync_replay_worker.py
|
||
database_fastapi.py # 写路由改走网关 + /sync/* API
|
||
```
|
||
|
||
### 同步 API
|
||
|
||
- `GET /database/sync/status`
|
||
- `POST /database/sync/binding/ensure`
|
||
- `GET /database/sync/binding`
|
||
- `GET /database/sync/pending`
|
||
- `POST /database/sync/replay` body: `{ "limit": 50 }`
|
||
|
||
请求头需带:`Database-ID`、`User-ID`(或应用已登录)、可选 `Tenant-ID` / `Authorization`。
|
||
|
||
### 写路径行为(`online_primary`)
|
||
|
||
```text
|
||
联网:先写线上(Database-ID=online_db_id)→ 成功再写本地镜像 → synced=true
|
||
离线 pending_log:不写正式本地业务结果 → 入 sync_pending 队列 → pending=true
|
||
离线 reject:直接失败
|
||
回放:按 id 升序提交线上 → 成功后写本地并删队列记录;失败即停保序
|
||
```
|
||
|
||
绑定键:`(tenant_id, user_id, local_database_id) → online_db_id`(全局唯一)。
|
||
|
||
---
|
||
|
||
## 一、原状结论(改造前)
|
||
|
||
| 项 | 原状 |
|
||
|----|------|
|
||
| 写入口 | `/database/permanent/table/data/insert\|update\|update/id\|delete`、`/permanent/sql` 等 |
|
||
| 落库方式 | 直接 `PermanentDatabaseManager`,**只写本地 SQLite** |
|
||
| 队列能力 | `queue_database_fastapi.py` 与 permanent **未打通** |
|
||
| 线上主写 / 断网日志 | **未实现** |
|
||
|
||
---
|
||
|
||
## 二、目标模型
|
||
|
||
```text
|
||
联网:API 写 → 先写线上主库 → 再写本地镜像
|
||
断网:API 写 → pending 日志(queue_database)→ 不 formal commit
|
||
恢复:有序回放到线上主 → 成功再对齐本地
|
||
```
|
||
|
||
硬约束:主写在线上;断网日志只能回放到线上主;断网窗口非强一致。
|
||
|
||
---
|
||
|
||
## 三~十、设计说明(保留)
|
||
|
||
原 P0–P4、响应约定、勿做事项、分阶段 M1–M4 已按上文落地;M5(SQL/导入全收口 + 冲突监控)待续。
|
||
|
||
与智建平台 dbsync:客户端强一致仍以「API 同步写线上」为准,不要只靠触发器异步 outbox 充当主路径。
|
||
|
||
本意见文档:`E:\project\ai建站\database_fastapi修改意见.md`。
|
||
实现目录:`yuhengyihao_client\yxd\app_fastapi\`。
|