← 中文资源

简体中文版本

添加 Outbox 中继

在业务事务中把事件写入 outbox,再通过带重试的中继发布未发送行,并由幂等消费者处理重复。

阅读英文原文

双写问题

服务先写数据库再发布事件。如果进程在两者之间崩溃,事件丢失;如果先发布而事务回滚,消费者会看到不存在行的事件。单独重试发布或提交都无法修复,因为两个系统不共享事务。

CREATE TABLE outbox (
  id bigserial PRIMARY KEY,
  aggregate_id text NOT NULL,
  event_type text NOT NULL,
  payload jsonb NOT NULL,
  created_at timestamptz DEFAULT now(),
  published_at timestamptz
);

用认领和重试中继

中继用 FOR UPDATE SKIP LOCKED 读取未发布行,发布后标记每一行。多个中继 worker 可以运行而不会认领同一行。发布失败会留下未发布行供之后重试。监控最老未发布时间;积压增长说明 broker 或中继在失败。

消费者必须去重

至少一次中继意味着消费者可能收到重复。使用消息 id 做事务化去重,并让业务效果幂等。发布顺序不保证,需要顺序的消费者应按聚合键分区。

验证中继

预期结果:事务提交后事件最终发布一次,事务回滚则不发布;中继崩溃后未发布行会被重试。用注入发布失败和重启中继的测试确认,并检查消费者重复投递只产生一次效果。