Agent 异步任务的事务消息:Outbox 与幂等消费 @ Lin | 2026-06-10T10:00:00+08:00 | 3 分钟阅读 | 更新于 2026-09-12T10:00:00+08:00

用事务内事件和消费去重衔接数据库与消息系统,明确至少一次投递下的责任边界。

本文于 2026-09-12 补充整理,按 2026-06 专题归档。示例为方案设计,参数用于说明方法,不代表已上线项目或实测成果。

双写窗口来自两个系统

用户提交任务时,应用需要把任务写入数据库,再通知消息队列。先写库后发消息,可能提交成功但消息丢失;先发消息后提交,消费者可能读到不存在的任务。

Outbox 的做法是把任务记录和待发送事件放进同一个本地事务,由独立投递器稍后发送。AWS 的模式说明介绍了这一核心思想。它提供可靠衔接的基础,但仍需要应用定义重复和顺序的处理方式。

事件与任务一起提交

以下是逻辑表结构示意:

CREATE TABLE task_outbox (
    event_id varchar(64) PRIMARY KEY,
    aggregate_id varchar(64) NOT NULL,
    aggregate_version bigint NOT NULL,
    event_type varchar(80) NOT NULL,
    payload text NOT NULL,
    created_at timestamp with time zone NOT NULL,
    published_at timestamp with time zone
);

同一数据库事务中插入任务和对应 outbox 记录。事件负载尽量只包含标识和必要字段,不放访问令牌或大段知识原文。消费者使用事件中的任务 ID,在自己的权限边界内读取当前状态。

事件需要明确 schema 版本。后续代码升级时,旧事件可能仍留在重试队列里,不能按新字段含义直接解释。

投递器会产生重复

投递器发送消息并收到 broker 确认后,更新 published_at。如果发送成功但更新前崩溃,下次会再次发送。这是正常恢复窗口,不能通过提前标记已发送来规避,否则会重新引入消息丢失。

多个投递器可采用短租约抢占记录,或结合数据库锁机制分批认领。不要让数据库事务在整个网络发送期间一直持有大量锁。认领超时、失败退避和卡住记录都要可观察。

消费去重必须绑定业务更新

消费者维护 consumer_name + event_id 唯一记录。在同一数据库事务中完成去重记录插入和本地状态推进,提交成功后才确认消息。若重复事件到达,读取已有处理结果并确认即可。

如果先记录“已消费”再单独执行业务,进程在两者之间崩溃会丢业务;如果先提交业务再记录去重,可能重复业务。所谓幂等消费需要精确到事务边界。

对外部工具调用,本地去重事务仍不能包住远程副作用。应进一步转化为带稳定操作 ID 的执行任务,再由工具幂等和结果对账处理。

顺序应由聚合版本校验

相同任务的事件可能出现版本 3 先于版本 2。消费者不能盲目按到达顺序推进状态。可以按任务 ID 分区降低乱序概率,同时用聚合版本做最终检查。

收到旧版本事件可以判定为已过时;收到超前版本时,选择等待缺失事件或读取任务权威状态进行协调。不能简单把所有超前消息丢掉,否则可能永久失去推进信号。

死信队列中的事件重放应保留原事件 ID,这样去重逻辑仍然有效。人工重放也不能跳过业务状态检查。

验证最重要的三个窗口

分别在数据库提交后、broker 确认后、消费者事务提交后杀掉对应进程。预期是事件最终可见,本地状态不会重复推进,外部写操作受独立幂等保护。

此外监控最老未投递事件的年龄,单看 outbox 行数不够:少量长期卡住的记录也可能对应重要任务。清理历史 outbox 前,要明确审计、重放和备份保留期限。

这套设计体现的是对失败窗口的管理,而不是给系统贴上“消息绝不丢失、恰好一次”的标签。


查看系列导读与阅读路线

© 2019 - 2026 Lin 的博客

Powered by Hugo with theme Dream.

avatar
关于我

Lin 的 ❤️ 博客

技术专题:Java Agent 工程化:从知识库问答到可靠业务执行。围绕 RAG、工具治理、任务恢复与 Java 平台架构整理设计思路和验证方法。

记录一些 🌈 生活上,技术上的事

  • 🛠️ 技术阵地: 深耕 Java 开发 ,目前向 AI 应用领域探索与拓展。这里主要记录我从后端架构到 AI 赋能的进阶之路、技术思考以及日常的 debug 血泪史。始终致力于写出优雅且没有 bug 的代码(尽量)。
  • 🌈 生活侧写: 偶尔脱下极客的外衣,我也会在这里分享生活中的灵光一现。不管是好用的效率工具,还是周末的一场骑行,都是构成我真实生活的一部分。