Skip to content
预计 1 分钟右侧目录可快速定位

Run/Node 发给 Worker 后会发生什么:Queue、Ack、Redelivery 与 At-least-once ​

前置:Outbox / Durable Dispatch;Run / Attempt Identity
核心问题:Tool 已成功、ACK 前 Worker crash,为什么 Broker 必须 redeliver,At-least-once 对业务意味着什么?

最关键的 Crash Window ​

text
Worker receives message
→ executes Tool side effect successfully
→ process crashes
→ ACK was never sent
→ broker redelivers message

这不是 broker “出错”,而是可靠交付系统必须面对的不可判定窗口:如果 broker因为没看到 ACK 就永远不重投,第一次 Worker 真正在执行前 crash 时消息又会永久丢失。

所以生产 Queue 常按 at-least-once 思维设计 consumer:消息可能重复到达。

一条消息的生命周期要明确 ​

Queue 最容易被误解成“放进去,Worker 取出来”两步。生产 Harness 真正需要知道的是消息在 Worker crash 前后会怎样变化。

text
publish
→ durable in broker
→ worker receives
→ processing / visibility lease
→ ack

如果 Worker 在 receive 后、ack 前 crash,多数 broker 会让消息重新可见。因此 redelivery 是正常语义,不是异常情况,Worker 必须用 stable execution identity 做幂等提交。

设计 Queue 时至少明确:何时算 durable、何时 ack、visibility/lease 多久、能否续租、ordering 范围以及 retention。否则无法推导 crash 后 Run 会不会丢、会不会重复。

Queue Message 不是 Canonical State ​

推荐消息只携带稳定定位信息:

json
{
  "run_id": "r-123",
  "node_id": "n-7",
  "dispatch_id": "d-88"
}

Worker 收到后:

text
load NodeState
→ still eligible?
→ deadline/cancel checked?
→ try_claim lease
→ only valid owner executes

因此重复消息只是“重复提醒”;无效/过期消息加载状态后直接丢弃。Queue 不需要维护完整 RunState,也不承担 fencing authority。

Lost Notification 也不能让 Run 永久卡死 ​

如果状态已经提交为 READY,但 enqueue 前 crash:

text
DB: READY
Queue: nothing

系统需要 durable bridge,例如 outbox,或者 scheduler/reconciliation scanner 定期重新发现 eligible work。

这和“Queue 重复投递”是同一原则:正确性来自 durable facts,可丢/可重复的 notification 只负责唤醒执行。

At-least-once 对 Harness 的直接要求 ​

  • Worker 必须有稳定 logical operation identity;
  • Tool side effect 需要 idempotency/reconciliation;
  • ACK 时点要晚于必要的 durable commit;
  • redelivery 不应直接创建新的业务 operation;
  • stale message 必须能被 Runtime state 判定为无效。

Failure Modes ​

收到 Queue Message 就直接执行 Tool ​

后果: 重投、乱序或重复 publish 产生多个有效执行者。

处理: message → load state → claim;只有最新 lease/epoch owner 执行并提交。

DB READY 已提交但通知丢失 ​

后果: Runtime truth 表示 Node 可运行,但没有 Worker 再被唤醒,Run 会长期停在 READY。

处理: 恢复触发本身必须具备 durable path;具体采用前文的 bridge 方案,并用 fault injection 验证 crash window。

如何验证 ​

Fault Injection必须成立
Tool 成功、ACK 前 kill workerredelivery 后业务效果不重复
READY commit 后、enqueue 前 crashscanner/outbox 最终重新 dispatch
同消息投递 3 次最多一个有效 execution owner

自测 ​

  1. Tool 已执行成功,但 Worker 在 ACK 前 crash。为什么 Broker 必须允许 redelivery,而不能假设消息“应该已经处理完”?
  2. At-least-once 接受重复投递后,哪一层必须承担去重/幂等责任,才能让重复消息不变成重复业务效果?

Sources ​

AI Engineering · Agent · Harness · Backend Systems