← 返回题目列表

补偿任务如何设计才可靠?

高频 中等 第 2 / 25 题 更新于 2026/09/30
补偿任务幂等最终一致性重试
学习 AI 实战项目

简化版

可靠补偿任务必须有权威状态、稳定业务键、幂等执行、可恢复进度和明确终态。 任务从异常事件、状态扫描或对账差异产生,经过抢占、条件检查、执行、结果确认和重试,不能只是无限循环定时器。 重试有退避与上限,永久失败进入人工队列,执行前重读当前状态以防迟到补偿覆盖新结果。

详细版

任务记录 taskId、businessKey、expectedVersion、动作、状态、attempt、nextRunAt、leaseOwner 和 lastError。 Worker 用租约或条件更新抢任务,外部动作带幂等键,完成时 CAS 更新状态。 若外部成功后进程崩溃,重试必须查询结果或幂等重复。 系统区分瞬时、限流、业务拒绝与永久错误,监控积压年龄、成功率、死信和不一致持续时间。

完整版教学

一、补偿不是简单重试

重试再次执行原动作,补偿也可能执行逆向或替代动作。 订单已创建但积分未发时可补发;支付已撤销时则可能需要取消积分。 任务必须围绕当前业务不变量决策。

补偿的目标是恢复正确业务状态,而不是机械回放旧请求。

二、任务数据模型

字段作用
businessKey唯一业务对象
expectedVersion防迟到覆盖
action/payload补偿意图
status/attempt状态与次数
nextRunAt退避调度
lease防并发领取

payload 保存必要引用,不复制可从权威源读取的敏感大对象。

三、状态机与租约

PENDING -> RUNNING -> SUCCEEDED
              |-> RETRY_WAIT -> RUNNING
              |-> MANUAL_REVIEW
              |-> CANCELLED

RUNNING 使用有限租约,Worker 崩溃后可重新领取。 终态保留审计,不能成功后立即删除。

四、幂等执行

taskId 或业务操作号传给下游作为幂等键。 下游在同一事务内记录去重键和业务结果。 响应丢失时查询原结果或重复同一幂等请求。 本地标记“发送过”不能证明下游成功。

五、执行前校验

任务创建时订单版本 7,执行时可能已到版本 10。 补偿应读取权威状态并检查 expectedVersion 和合法前置条件。 状态已自然恢复则标记 RESOLVED。 状态走向相反则取消或转人工,不能回写旧状态。

六、重试与限流

瞬时故障按 5 秒、30 秒、2 分钟等节奏退避并加抖动。 参数非法、账户冻结等永久错误不应无限重试。 下游限流时遵循 Retry-After,避免补偿流量加重故障。 到达次数或时间上限后进入人工队列。

七、扫描与观测

按 nextRunAt 索引分页领取,使用游标而非深分页。 分片归属要稳定,扩容时仍靠租约与幂等保护。 监控 oldest_pending_age、到期积压、attempt 分布和人工积压。 独立对账负责发现任务创建链路本身漏掉的异常。

八、常见误区与追问

  • 误区:失败就无限重试最可靠。 永久错误会形成重试风暴。
  • 误区:单实例任务不需要幂等。 崩溃和响应丢失仍会重复。
  • 误区:补偿按创建时数据执行即可。 当前状态可能已变化。
  • 误区:任务成功后立刻删除。 会失去审计与结果查询。
  • 追问:外部成功、本地未记成功怎么办? 用幂等键查询或重复。
  • 追问:怎样避免多 Worker 重复? 租约领取加下游幂等。
  • 追问:任务漏创建怎么办? 权威状态扫描和独立对账再生任务。

九、加强记忆

  1. 补偿围绕业务不变量。
  2. 任务有状态机、租约、进度和审计。
  3. 下游动作使用稳定业务键幂等。
  4. 执行前重读状态,防迟到覆盖。
  5. 重试有退避和人工终点,对账负责补漏。