feat: 任务改用采集采购独立序号 (#172)

This commit is contained in:
chengma
2026-08-12 09:21:21 +08:00
parent eca3a77084
commit 9ad067503e
15 changed files with 523 additions and 44 deletions
+29 -5
View File
@@ -110,7 +110,9 @@ SQLite 同一时刻只允许一个写事务,连接放太开会互相抢锁、
生产 MySQL 迁移继续独立追加;v12(#165)新增 `task_syb_sources`,并把没有任何
有效采集任务的孤立 `pdd_products.collect_status='collecting'` 回收到 `pending`。
历史 SQLite migrations 保持冻结,不追加该表。
v13(#172)新增 `task_sequences`,把存量 `tasks.task_id` 按类型和创建时间确定性改为
`cjN` / `cgN`,同步更新领取历史和顺运宝来源外键。历史 SQLite migrations
保持冻结,不追加 v12/v13 生产表结构。
**v3 为什么丢弃旧 `sku_mappings` 数据(见 #20):** 新主键需要 `pdd_option_key`,
这是 Go 的 `service.OptionKey()` 用 `json.Marshal` 算出来的规范化键,SQL 语句
@@ -631,7 +633,7 @@ FROM spec_mapping_decisions WHERE suggested_option_key IS NULL GROUP BY rules_ve
```sql
CREATE TABLE tasks (
task_id TEXT PRIMARY KEY, -- 给 Client 的稳定编号,如 PDD-20260806-0001
task_id TEXT PRIMARY KEY, -- 稳定业务主键:采集 cjN,采购 cgN
task_type TEXT NOT NULL CHECK (task_type IN ('collect', 'purchase')),
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'assigned', 'claimed',
@@ -671,6 +673,10 @@ CREATE INDEX idx_tasks_list ON tasks(updated_at DESC, task_id DESC);
CREATE INDEX idx_tasks_order ON tasks(order_no);
```
`task_id` 不是另外的展示别名,而是真实主键。采集和采购分别从 1
开始递增,不共用计数器。分配编号与插入任务必须在同一事务中,以避免
并发重号和创建失败消耗序号。Client 应把这个值当作不透明字符串原样保存。
生产 MySQL v5 在 `tasks` 追加以下安全字段(历史 SQLite 结构不改):
| 字段 | 含义 |
@@ -703,7 +709,21 @@ CREATE INDEX idx_tasks_order ON tasks(order_no);
状态含义见 [01 需求](01-requirements.md) §6.2。
### 7.1 `task_syb_sources` 采集任务来源(生产 MySQL v12)
### 7.1 `task_sequences` 任务序列(生产 MySQL v13)
```sql
CREATE TABLE task_sequences (
task_type VARCHAR(20) COLLATE utf8mb4_bin PRIMARY KEY,
current_value BIGINT NOT NULL DEFAULT 0,
CHECK (task_type IN ('collect', 'purchase')),
CHECK (current_value >= 0)
);
```
表中只有 `collect` 和 `purchase` 两行。创建任务时先在当前事务内对对应行
`current_value + 1`,再读取并组成 `cjN` 或 `cgN`;InnoDB 行锁保证并发唯一。
### 7.2 `task_syb_sources` 采集任务来源(生产 MySQL v12)
从顺运宝创建采集任务时,同一个 PDD 商品可能对应多个货运单明细。来源使用关联表,
不能压进 `tasks.syb_id` 单列;后者仍只表示采购任务自身的顺运宝明细。
@@ -715,7 +735,7 @@ CREATE TABLE task_syb_sources (
created_at VARCHAR(35) NOT NULL,
PRIMARY KEY (task_id, syb_id),
KEY idx_task_syb_sources_syb (syb_id, task_id),
FOREIGN KEY (task_id) REFERENCES tasks(task_id) ON DELETE CASCADE,
FOREIGN KEY (task_id) REFERENCES tasks(task_id) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (syb_id) REFERENCES syb_orders(syb_id) ON DELETE CASCADE
);
```
@@ -735,12 +755,16 @@ CREATE TABLE task_claims (
task_id TEXT NOT NULL,
client_id TEXT NOT NULL,
claimed_at TEXT NOT NULL,
PRIMARY KEY (task_id, client_id)
PRIMARY KEY (task_id, client_id),
FOREIGN KEY (task_id) REFERENCES tasks(task_id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX idx_task_claims_client ON task_claims(client_id);
```
生产 MySQL v13 清理了无对应任务的孤儿领取历史,并加入上述外键;
`ON UPDATE CASCADE` 保证主键迁移时领取历史同步改号。
**为什么需要这张表:** [04 Client 接口实现](04-client-api.md) §4.1 要求
"只有**从未分配给该客户端**的任务才返回 403"。
但 `tasks.assigned_client` 只记**当前**归属,任务一旦重派给别人,