【问题标题】:DDD dealing with Eventual consistency for multiple aggregates inside a bounded context with NoSQLDDD 使用 NoSQL 在有界上下文中处理多个聚合的最终一致性
【发布时间】:2023-04-06 07:10:01
【问题描述】:

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

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

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

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

我正在使用一个名为 MediatR 的库,而据我所知的 INotificationHandler 是“一劳永逸”

编辑: 最终找到了这个 SO post,它准确地描述了我所需要的(传奇/流程管理器),但不幸的是,我无法找到任何类型的 Saga 实现来处理同一事件中的事件公元前。我看到的所有示例都涉及服务总线。

【问题讨论】:

    标签: events redis event-handling domain-driven-design mediator


    【解决方案1】:

    相同或不同的限界上下文;有或没有 Sagas;没关系。

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

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

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

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

    事件模拟:

    • Agg1:嘿伙计们!用户做了这件很酷的事情,一切似乎都很好。 --> UserDidThisCoolThingEvent
    • Agg2:哇,太棒了!我要在用户积分中加上+3。 --> UserRecibedSomePointsEvent
    • Agg3:+3 分给这个用户?用户刚达到100分。那是很多!我要将此用户转换为 VIP 用户。 --> UserTurnedIntoVIPEvent
    • Agg4:新的 VIP 用户?让我们将它通知给其他用户,以制造理智的嫉妒;)

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

    短时间自动重试失败。 ErrorQueues/Logs 在长时间中断时不会丢失您的事件(并在以后应用它)。

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

    【讨论】:

    • 我同意这一点,但在跨聚合更改的情况下不同意。聚合应该能够保护自己不被要求达到不一致的状态,包括如果更改最初是由另一个聚合的事件引起的。 IMO,聚合级联更改应通过中间命令。您不应该直接订阅另一个聚合的事件,并将它们视为与您自己的一样安全。
    • @jlvaquero 我应该提到我专门指的是处理基础设施故障。我在我的主聚合根中强制执行所有不变量,以确保域规则不会失败。我确实有日志记录和事件溯源,但我不确定如何利用这些来实现长期基础设施中断的最终一致性。我将尝试对此进行更多研究,并研究错误队列,因为我不熟悉这个概念。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 2014-08-22
    • 2020-09-07
    • 2021-05-29
    • 2016-07-11
    相关资源
    最近更新 更多