我正在设计一个具有多个有限上下文(微服务)的系统。我将有2种活动。
Domain Events
,发生在单个事务(同步)中的“内存中”]Integration Events,
在有界上下文之间使用(异步)我的问题是,如何确保一旦提交事务(此时我确定所有Domain Events
已成功处理),Integration Events
也同样成功。
[当我提交事务时,通常我会分派Integration Events
(例如,到队列),但是该队列也可能会关闭,因此以前“刚刚提交的事务必须被“还原”。怎么样?
我想到的唯一解决方案是将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/之后,作者实际上建议在同一数据库中使用“预先排队”的方法(他称其为“准备发布事件”)。
[结帐transactional outbox pattern。
此模式确实会创建一个预队列。但最棒的是,将消息从预队列推送到真实队列是完全分离的。相反,您有一个称为“中间人”的消息中继,该消息中继读取您的事务日志并将事件从其推送到实际队列中。现在,由于发送消息和您的域事件已完全解耦,因此您可以在单个事务中处理所有域事件。
并且请确保您的所有服务都是一致的(即使有重复的呼叫,结果也一样)。此事务发件箱模式确实可以保证消息已发布,但是如果消息中继在发布后(确认之前)失败,则它将再次发布同一事件。
在其他情况下,全能服务也是必要的。由于事件总线(实际队列)可能有相同的问题。事件总线传播事件,服务确认,然后发生网络错误,然后由于未确认事件总线,因此将再次发送相同的事件。
嗯,实际上等幂可以解决整个问题。域事件计算完成(单个事务)后,如果发布消息失败,则服务可以简单地引发错误而无需回滚。由于未确认事件,因此事件总线将再次发送相同的事件。现在,由于该服务是幂等的,因此同一数据库事务将不会发生两次,它基本上将被覆盖或更好(应该)跳过并直接移至消息发布和确认。