标准答案

  1. outbox 记录保存事件 ID、类型、载荷、状态、重试次数和下次尝试时间。
  2. 领取时用条件更新或租约避免多个发布器长期处理同一记录。
  3. 发送成功与标记成功之间允许重复,失败使用退避、死信和告警,不能静默删除。

题目解析

Outbox 把业务变更和事件记录写入同一个数据库事务,确保业务提交后一定有可扫描的待发事件。发布器再负责领取、投递、重试和标记发送。

领取需要租约或条件更新,防止多个发布器长期处理同一条;发送成功与 markSent 之间可能崩溃,因此重复发送是预期行为,消费者必须幂等。

发布器还要处理批次、顺序、死信、过期事件、清理和监控。markSent 只表示消息已经被发布器确认,不表示消费者业务已经完成。

代码示例

发布器的核心状态转换:

TypeScript
const batch = await claimOutbox({ status: "pending", leaseUntil: now })
for (const event of batch) {
  try {
    await broker.publish(event.id, event.payload)
    await markSent(event.id)
  } catch (error) {
    await scheduleRetry(event.id, error)
  }
}

常见误区

  • 误区:扫描后直接发送没有租约。改正:先原子领取并设置 leaseUntil,避免多个发布器无边界重复发送。
  • 误区:发送异常删除 outbox。改正:保存失败原因和下次重试时间,超过阈值进入死信或人工处理。
  • 误区:把 markSent 成功当作消费者业务成功。改正:区分发布确认和消费结果,使用消费者幂等与状态查询闭环。

作者信息