【发布时间】:2016-04-08 16:34:57
【问题描述】:
我正在使用熟悉的事件溯源模式构建服务:
- 收到请求。
- 已加载聚合的历史记录。
- (根据其历史)重建聚合。
- 准备新事件并更新聚合以响应来自步骤 1 的传入请求。
- 这些事件被写入日志,并可供任何订阅者使用(发布)。
在我的例子中,步骤 5 分两部分完成。事件将写入事件日志。后台进程从事件日志中读取并发布从偏移量开始的所有事件。
在某些情况下,除了与聚合相关的事件之外,我还需要发布副作用。就系统而言,这些也是事件,因为它们被其他服务消费并影响其他服务的状态。但是,它们不会影响此服务中聚合的历史记录,也不需要重建它。
我应该如何在代码中处理这些?
选项 1- 不要将副作用事件写入事件日志。在第 5 步之前的主流程中发布这些。
选项 2- 将所有内容写入事件日志并在加载历史记录时忽略副作用事件。 (这些不是历史的一部分!)
选项 3- 将副作用事件写入虚拟聚合,以便发布它们,但从不加载。
选项 4- ?
在第一个选项中,如果存在并发冲突,可能会出现问题。如果第 5 步写入失败,那么副作用就不能轻易回滚。第二个选项写入不属于聚合历史的事件。在步骤 2 中加载时,必须忽略这些副作用事件。第三个选项感觉就像一个黑客。
你觉得哪一个合适?
【问题讨论】:
-
您通常会选择选项 2。假设您有您的事件源应用程序,例如银行和第二个应用程序统计信息,它们根据第一个应用程序中发生的事件构建统计信息。假设统计应用订阅了您的“副作用事件”。在不保存该事件的情况下,一切都会正常工作,直到您的企业说:“我们希望将它们作为单独的系统出售”。现在你的一些客户在使用银行应用两年后会购买统计应用,如果你不将之前的“副作用事件”保存到 ES,你会错过一些概念,甚至会同步失败。
-
@CharlesR 你能举出这种“副作用”的具体例子吗?我不确定为什么不影响任何聚合状态的东西首先应该被视为域事件......
-
@guillaume31汇总为“合作伙伴欠款”。这是我们需要收回的钱。我们不是直接向客户收费,而是从我们将来寄给他们的钱中取出。在我们分配资金之前,我们会检查合作伙伴是否欠钱,并收回他们所欠的款项。然后我们发布领域事件来更新合作伙伴的现金余额并分配任何资金。从该服务的 POV 来看,这些是请求或副作用。我们需要发布它们,但它们不会影响聚合的状态(欠合作伙伴金额)。
-
我不确定这里的事件顺序。如果我让你好了,你是说
PartnerAmountOwed.Reduced应该触发PartnerCashBalance.Update()和Funds.Distribute()。我会反过来做。 -
除了“我们需要发布它们”,当然,但是
PartnerAmountOwed聚合不应该发布它们。它应该不知道会波及其他聚合的副作用,并坚持自己的内部无处不在的语言和事件。
标签: domain-driven-design event-sourcing event-driven-design