外观
异步任务、版本、幂等与恢复
1. 解决什么问题
模型、图片和音频可能超时,worker 可能退出,用户也可能在素材制作中修改内容。可靠执行要处理“重复请求、执行结果不明、旧结果迟到”,不能只在异常后重新调用一次。
2. 原理与术语
幂等键识别同一业务意图;租约限制 worker 持有任务的时间;心跳延长租约;fencing 令牌阻止旧执行者提交任务状态。业务版本决定哪些结果可交付,文件 receipt 则帮助恢复已经落盘但未完成数据库记录的素材。
3. 输入输出与执行
claim 用 FOR UPDATE SKIP LOCKED 领取可运行且依赖已完成的任务,增加 attempts 并生成 lease_token。执行发生在短事务之外,完成时只有仍持有令牌的 worker 能提交。状态包括 ready、running、retry、unknown、failed、succeeded、superseded。
4. 容易混淆
超时不等于外部服务没执行;租约过期也不能撤销已经发出的请求。任务去重不保证供应商只收费一次。Checkpointer 管流程,任务表管调度,教材版本管发布事实,三者不能相互替代。
5. 最小示例
python
from app.db import digest
assert digest({"kind":"audio","text":"你好"}) == digest({"text":"你好","kind":"audio"})
assert digest({"version":1}) != digest({"version":2})稳定摘要只是识别输入的基础,真正并发去重依赖数据库唯一约束,不能用一次字典查询替代。
6. 实际实现
自动重试受 MAX_ATTEMPTS 限制,退避为指数增长并封顶 30 秒,当前没有随机抖动。真实图片或 TTS 的超时、网络错误和部分服务错误进入 unknown。恢复先检查本地持久 receipt;当前适配器没有供应商任务查询能力,缺证据时不能自动重发。
7. 源码与数据结构
阅读 system/app/worker.py::claim/heartbeat/recover_expired/run_once、db.py::enqueue/save_version、media.py::reconcile 和 api.py::resolve。tasks 的 dedup_key、lease_token、available_at、version 分别承担不同责任。
8. 取舍与边界
新内容版本将旧未完成素材标记 superseded;交付检查只接受当前批准版本的完整任务集合。素材文件按输入指纹存储,可复用相同输入。真实外部结果不明时要求用户明确接受重复风险再重试,承认边界比虚构恰好一次可靠。
9. 实验与验收
演示模式创建故障场景并通过人工审核:
bash
curl -s -H "X-API-Key: ${LAB_API_KEY:-}" -H 'Content-Type: application/json' \
-d '{"theme":"校园生活","scenario":"media_timeout"}' http://127.0.0.1:8000/api/jobs检查图片首次安全注入失败、attempts 增加、随后成功。再编辑一个课文块并重新审核,比较新旧任务版本与复用事件。该超时发生在演示提交前,不能用它证明真实服务超时后自动重试安全。
10. 故障排查
任务不领取先查依赖、available_at 和 attempts;running 长期不结束查心跳;unknown 查 receipt;旧结果问题查 current_version 和 lease_token。人工重试会重新开放尝试预算,但操作应有记录,不应把反复点击当成自动恢复策略。
11. 面试题与追问
问:如何防止旧结果覆盖新版本? 旧任务失效、提交令牌检查、交付版本门同时约束。追问:外部已成功但程序没收到呢? 核对持久结果,无法确认则保留 unknown。再追问:为什么不承诺 exactly-once? 数据库事务无法原子覆盖第三方 API;没有对方幂等或查询契约时存在不可消除的不确定窗口。
STAR 应用:假设实验场景,R 为应核对的证据
| 对应 | S:情境 | T:目标 | A:行动 | R:验收证据 |
|---|---|---|---|---|
| 主问 | 旧worker完成过期任务 | 阻止旧状态覆盖 | 核对版本与租约令牌 | 旧任务不能使当前版本交付成功 |
| 追问一 | 供应商成功但响应丢失 | 避免盲目重复付费 | 核对receipt;缺证据保留unknown | 明确结果不明而非静默重发 |
| 追问二 | 被要求承诺恰好一次 | 说明外部事务边界 | 区分本地去重与供应商契约 | 列出仍需人工核对的失败窗口 |
这些是设计讨论的参考表达,实际执行前不能改写为已取得的历史成果。
12. 官方资料与版本
PostgreSQL 16 SELECT、显式锁、AWS 幂等重试。核验日期 2026-11-03;当前实现是数据库任务队列,不声称使用 Celery 或外部消息中间件。