标准答案

  1. 建立 `(source, event_id)` 唯一约束,重复插入表示已经受理或处理。
  2. 处理状态包含 processing、succeeded、failed 和租约,消费者崩溃后允许过期任务恢复。
  3. 业务写入和幂等记录尽量放在同一事务;跨系统副作用仍要用业务幂等键和回查。

题目解析

消费幂等记录要同时承担去重、处理中租约、最终结果和审计证据。source + event_id 唯一约束先阻止并发重复抢占,processing 超时后才允许其他消费者接管。

业务写入和幂等记录能放在同一数据库事务时,崩溃后容易判断是否已经完成;跨系统副作用仍可能重复,需要业务幂等键、状态查询或补偿。

ACK 只能表示消息处理结果已经达到约定边界,不能因为“见过事件”就直接确认。保留期要覆盖消息重放和对账窗口,失败记录不能静默删除。

代码示例

唯一约束和状态抢占示意:

sql
INSERT INTO consumed_event(source, event_id, status)
VALUES (:source, :id, 'processing')
ON CONFLICT (source, event_id) DO NOTHING;

常见误区

  • 误区:用消息到达时间做唯一键。改正:使用发送方提供的稳定 event_id 和 source,时间只能作为辅助字段。
  • 误区:重复消息直接 ACK 却没有确认原处理结果。改正:查询幂等记录和业务状态,区分已成功、处理中和失败。
  • 误区:幂等记录和业务写入分属事务却没有补偿。改正:设计 Outbox、回查和对账,明确跨系统失败窗口。

作者信息