标准答案
- outbox 记录保存事件 ID、类型、载荷、状态、重试次数和下次尝试时间。
- 领取时用条件更新或租约避免多个发布器长期处理同一记录。
- 发送成功与标记成功之间允许重复,失败使用退避、死信和告警,不能静默删除。
题目解析
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 成功当作消费者业务成功。改正:区分发布确认和消费结果,使用消费者幂等与状态查询闭环。