在事务中的聚合中发布事件

时间:2014-03-21 02:24:42

标签: cqrs

我见过使用ORM持久化的有状态聚合根的CQRS示例项目。让我在网络应用程序的上下文中设置问题:

  1. 收到请求 - 隐含会话& sql事务开始(每个请求的会话)
  2. 命令根据请求
  3. 创建和分派
  4. 命令处理程序使用repo加载有问题的AR并在AR上调用适当的方法
  5. 在方法中使用总线引发/发布事件
  6. 请求终止 - 如果管道中没有异常,则隐式事务提交
  7. 我的问题围绕事件发布,在隐式事务未能提交的上下文中。如果没有更新AR的实际状态,那么发布的事件是不是一个大问题?如果是这样,怎么能解决这个问题?

2 个答案:

答案 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阶段提交的需要,并且允许将状态更改传递给观察者。