重点:幂等、可回放、可恢复。把“失败”视为一等公民。
🎯 文章目标
- 设计长任务的状态机与检查点
- 定义重试与补偿策略,确保一致性
- 提供最小实现与观测指标
📚 背景/前置
- 长任务:分钟/小时级,跨多服务/工具,易失败
- 失败类型:网络/配额/权限/数据质量/超时/中断
🔧 核心内容
1) 状态与检查点
- 状态机:pending → running → succeeded/failed/cancelled
- 检查点:在关键步骤持久化(输入/输出/偏移量)
- 幂等键:避免重复执行副作用
2) 重试与补偿
- 指数退避 + 最大尝试次数;按错误类型决定是否可重试
- 补偿动作:对外部系统的副作用需“反向操作”或“标记撤销”
- 超时/中断恢复:从最近检查点恢复
3) 观测与告警
- 指标:平均耗时、失败率、重试次数、卡点分布
- 告警:重试过多/长期 pending/同类错误爆发
💡 实战示例:异步队列 + 状态机(Node.js)
javascript
import Queue from 'bull'
const q = new Queue('long-job')
q.process(async (job)=>{
const { steps } = job.data
for (const s of steps){
// 幂等:不要重复执行副作用
if (await done(job.id, s.name)) continue
await doStep(s)
await checkpoint(job.id, s.name)
}
})
📊 对比/取舍(速查)
- 同步:简单但易超时;
- 异步:复杂但可恢复,建议用于长任务
🧪 踩坑与经验
- 无幂等键导致重复执行;
- 无检查点导致中断无法恢复;
- 无观测导致故障不可见
📎 参考与延伸
- Saga/补偿事务、Outbox/Inbox 模式
- 任务队列与工作流引擎(Bull/Temporal/Airflow)
💭 总结
- 以“状态机 + 检查点 + 幂等 + 重试/补偿 + 观测告警”,构建可恢复的长任务