DB Transaction and Integrations Events dispatch - 如何让它成为原子?

DB Transaction and Integrations Events dispatch - how to make it atomic?

我正在设计一个具有多个限界上下文(微服务)的系统。我会有2种活动。

我的问题是,如何确保事务一旦提交(此时我确定所有 Domain Events 都已成功处理)Integration Events 也成功。

当我的事务提交时,通常我会调度Integration Events(例如到队列),但也有可能这个队列也关闭了,所以之前刚刚提交的事务必须是"reverted"。怎么样?

我想到的唯一解决方案是将 Integration Events 存储到同一个数据库,在同一个事务中,然后处理 Integration Events 记录并将它们推送到队列 - 这将类似于“使用当前数据库作为预队列,然后将其推送到 The Real Queue(但是我读到使用 DB 是一种反模式)。

是否有任何模式(可靠的方法)来确保:事务提交推送到队列的消息是原子操作?

编辑 在阅读 https://devblogs.microsoft.com/cesardelatorre/domain-events-vs-integration-events-in-domain-driven-design-and-microservices-architectures/ 之后,作者实际上建议在同一个数据库中使用 "pre-queue" 的方法(他称之为“准备发布事件”)。

结帐transactional outbox pattern

此模式确实创建了一个预队列。但好的部分是将消息从预队列推送到真实队列是完全解耦的。相反,您有一个称为中间人的消息中继,它读取您的事务日志并将您的事件推送到真实队列。现在,由于发送消息和您的域事件完全分离,您可以在单个事务中完成所有域事件。

并确保您的所有服务都是幂等的(尽管重复调用但结果相同)。这种事务性发件箱模式确实保证消息已发布,但如果消息中继在发布后(确认之前)失败,它会再次发布相同的事件。

其他场景也需要幂等服务。由于事件总线(真正的队列)可能有同样的问题。事件总线传播事件,服务确认,然后网络错误,然后由于事件总线未确认,将再次发送相同的事件。

嗯,实际上仅靠幂等性就可以解决整个问题。在域事件计算完成后(单个事务),如果发布消息失败,服务可以简单地抛出错误而不会回滚。由于事件未得到确认,事件总线将再次发送相同的事件。现在由于服务是幂等的,相同的数据库事务不会发生两次,它基本上会覆盖或者更好(应该)跳过并直接移动到消息发布和确认。