我见过使用ORM持久化的有状态聚合根的CQRS示例项目。让我在网络应用程序的上下文中设置问题:
我的问题围绕事件发布,在隐式事务未能提交的上下文中。如果没有更新AR的实际状态,那么发布的事件是不是一个大问题?如果是这样,怎么能解决这个问题?
答案 0 :(得分:2)
在处理CQRS和域事件时,有两件事情很重要:幂等性和最终一致性。在这种情况下,你真的没有ACID交易,你有没有处理过的消息。每个消息处理都是独立的(事件不了解命令或其他事件)。 '交易'实际上是处理发送的命令。通常情况下,事件是命令处理的结果,但事务'事件发布后结束,未处理。
如果服务器崩溃,服务总线/消息处理器应该检测到命令没有被发送/处理,并且应该尝试重新发送它(这里的idempontency非常重要)。与事件处理相同。
在您的示例中,您正在谈论提交(以db为中心的概念),但可以有2个命令更新执行异步的不同AR。如果一个命令失败,另一个命令不知道。这似乎很难处理,但它很简单,但概念和用例必须正确建模,因为你现在正在处理最终的一致性。
当命令从业务角度失败(违反业务规则)时,就会发布一个新事件,其处理程序将发出补偿操作(听起来并不是那么难)。所有相关方都将订阅该活动并采取相应行动。
当您对业务流进行建模时,如果您需要将2-3个命令视为事务处理,则需要了解这些命令之间是否存在业务关系。有些可能是无关的,但其他可能实际上是传奇的一部分。因此,您在拥有cmd1的交易中没有3个命令 - >事件 - > cmd 2->事件 - > cmd3。只有在最后,'交易'完成了。
商业模式告诉您哪种情况(正确建模的重要性),这将有助于您解决问题,因为您不必撤消3个命令和N个事件。
答案 1 :(得分:0)
所以我的问题源于这个事实,即基本上有两个阶段的“提交”。在此示例中,P1 =已发布事件,P2 = AR状态持久保存到数据库。没有其他事情发生的任何事情都会导致不一致。
没有完美的方法可以解决这一特定问题,但我找到了利用事件存储机制的有前途的替代方案。
通过这种方法,AR维护已经应用的事件的内部列表(通常通过执行的命令)。这些事件不是持久保存AR的当前状态,而是单独保存到事件存储中。当前状态永远不会保留,但可以通过重播事件来恢复。
当事件存储保持状态更改时,这消除了对2阶段提交的需要,并且允许将状态更改传递给观察者。