# Import worker 持久 lease 验证报告 更新时间:2026-07-12 ## 结论 `content_import_jobs` 已具备多实例和进程重启所需的持久 lease 与 fencing 语义。验证只在专用测试库 `127.0.0.1:55432` 执行,没有连接生产环境。 ## 实现边界 - migration `202607120016_content_import_job_leases.sql` 增加 `lease_token`、`lease_expires_at`、`last_heartbeat_at`、一致性约束和 pending/expired 部分索引。 - claim 使用原子 `SKIP LOCKED`,可同时领取 ready pending job 和 lease 已过期的 importing job。 - 每次 claim 只增加一次 `attempt_count` 并生成新 token;失败调度只写 `next_attempt_at`,不会重复增加 attempt。 - worker 在执行期间续租;续租、完成、失败和重试都要求 token 匹配且 lease 未过期。 - API executor 的业务写入和终态更新处于同一事务。fencing 校验失败会回滚题目、版本、集合绑定、item 和 audit 写入。 - 最后一次 attempt 的 lease 过期后由 claim/reaper 路径直接标记 failed,避免第 `max_attempts + 1` 次执行。 ## 动态覆盖 `scripts/import-worker-integration-test.js` 在 destructive-test database guard 后验证: 1. 两个并发 worker 对三个 job 原子 claim,没有重复领取。 2. 心跳推进 `last_heartbeat_at` 并延长 `lease_expires_at`。 3. 模拟崩溃后,过期 job 被新 worker 接管,token 旋转且 attempt 从 1 变为 2。 4. 旧 token 的执行在业务写入前被拒绝,旧 token 的失败提交也不能覆盖新 lease。 5. 新 lease 可完成 job,终态清空 lease 字段并保持准确 attempt。 6. retry 保持 pending、持久 `next_attempt_at`,再次 claim 才增加 attempt。 7. 最后 attempt 过期后进入 failed,不再重新执行。 ## 验证命令 ```bash npm run check:worker npm run check:api npm run build:worker DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:55432/postgres \ node scripts/import-worker-integration-test.js \ --confirm=SMOKE_SEED_LOCAL_OR_CI_ONLY node scripts/production-readiness-check-test.js ``` 完整 worker integration 会先跑 smoke seed;执行时必须明确指向允许 destructive tests 的本地/CI 数据库。