DDD 使用 NoSQL 处理有界上下文内多个聚合的最终一致性

Jos*_*h L 4 events domain-driven-design event-handling mediator redis

我目前正在开发一款 DDD 地理定位应用程序,该应用程序在一个有界上下文中具有两个单独的聚合根。由于频繁的坐标更新,我使用 Redis 来保存不允许回滚的数据。

  1. 我的第一个聚合根是一个行程对象,其中包含司机(用户)、乘客(用户列表)等。
  2. 我的第二个聚合根是用户位置更新

当发送坐标更新时,我将生成并触发“UpdateUserPostionEvent”。作为副作用,我还将在某个点生成并触发“UpdateTripEvent”,这将更新驾驶员/乘客的坐标。

我的问题是,如果我异步触发“UpdateLiveTripEvent”,如何处理最终一致性。我的 UpdateLiveTripEventHandler 有几个故障点,除了记录错误之外,我该如何处理这种不一致?

我正在使用一个名为MediatR 的库和 INotificationHandler 据我所知是“Fire and Forget”

编辑:最终找到了这篇 SO帖子,它准确地描述了我需要的内容(saga/流程管理器),但不幸的是我无法找到任何类型的 Saga 实现来处理同一 BC 内的事件。我看到的所有例子都涉及服务总线。

jlv*_*ero 5

相同或不同的限界上下文;有或没有 Sagas;不要紧。

为什么事件处理失败?域规则或基础设施。

域规则:由聚合处理的引发事件(事件处理程序使用聚合来应用事件)不应根据域规则而失败。

如果“目标”聚合具有拒绝该事件的域规则,则您的聚合设计是错误的。命令/操作可以被域规则拒绝。域规则不能拒绝(也不能撤消)事件。

当“origin”聚合检查了此操作的所有域规则时,应引发事件。“目标”聚合应用事件,并可能引发另一个事件,其中包含由“目标”聚合计算的某些值(域规则,但不是用于拒绝事件;事件是域规则不可拒绝的;而是为了“继续”一致性“链” “具有良好的责任分离)。这就是为什么事件应该有过去的句子作为名称的原因;因为已经发生了。

事件模拟:

  • Agg1:嘿伙计们!用户做了这件很酷的事情,一切似乎都很好。--> UserDidThisCoolThingEvent
  • Agg2:哇哈哈,太棒了!我将在用户积分中添加+3。--> UserReceivedSomePointsEvent
  • Agg3:+3 分给该用户?用户刚刚达到100分。那是很多!我要将此用户转换为 VIP 用户。--> 用户变成 VIP 事件
  • Agg4:新的 VIP 用户?让我们通知其他用户以引起一些羡慕;)

基础设施:修复它并应用事件。;) 一旦您的持久性引擎、网络和/或机器再次启动,如果需要,甚至可以“手动”。

短时间自动重试失败。错误队列/日志不会在长时间中断时丢失事件(并稍后应用)。

事件源也对此有所帮助,因为您始终可以在“目标”聚合中重新应用持久化事件,而无需额外努力将事件保留在某处(即事件日志),因为您的域持久性也是您的事件存储。

  • @jlvaquero 我应该提到我特意指的是处理基础设施故障。我正在我的主聚合根中强制执行所有不变量,以确保域规则不会出现故障。我确实有日志记录和事件源,但我不确定如何利用这些来实现长期基础设施中断的最终一致性。我将尝试对此进行更多研究并研究错误队列,因为我不熟悉这个概念。 (2认同)