【问题标题】:Create multiple aggregates in one transaction在一个事务中创建多个聚合
【发布时间】:2019-12-04 18:16:03
【问题描述】:

我的有界上下文(库存)收到一个数量为 5 的事件。其中 5 是从仓库中的卡车上卸下的托盘数量。现在,在我的库存 BC 中,我想创建 5 个聚合(对于每个托盘 1 个聚合)。我怎样才能在我的应用层做到这一点?如果我只成功创建了 3 个呢?我无法过渡创建它们,因为我的持久存储是基于文件的。我该怎么办?

【问题讨论】:

  • 这是一个非常广泛的问题。这很难回答,因为你没有给出任何有意义的,甚至是矛盾的环境细节。标记实体框架和使用基于文件的数据库不会计算。我认为您不会使用为 EF 进行单元测试而设计的基于文件的数据库。

标签: entity-framework architecture transactions domain-driven-design ddd-repositories


【解决方案1】:

您可能应该将接收事件的记录和五个托盘的生成视为两个单独的事务。

在您的情况下,更改涉及两个聚合,但您的应用程序服务在理想情况下应该尽可能多地处理一个聚合。 域事件是解决此类扩展事务问题的正确结构,无论是单个 BC 中的聚合之间,还是跨 BC 的。

因此,您的应用程序服务会将五个托盘的接收记录为一个事务,并使用足够的上下文和数据生成一个域事件(例如 PalletsUnloaded)。该事件将作为数据结构传递给消息代理,以供为域事件注册的订阅者检索。

然后,Pallet 聚合将通过特定于事件的订阅者捕获事件并以两种方式之一对其进行处理:

  1. 您可以一次创建五个托盘。在事务方面,这种方法有点冒险,因为如果您使用文件作为持久存储,可能会出现故障,并且您可能没有细粒度的数据来识别确切的问题
  2. 您捕获该事件并创建五个单独的事件消息(例如CreatePallet),每个消息都提交回消息代理。此事件的订阅者将接收它们并一一创建托盘记录。您将准确地知道哪一个失败以及原因

第二种方法也更安全,因为如果您使用可靠的消息代理(如 RabbitMQ)作为事件传输机制,您可以将错误事件发送到死信队列或设置机制以稍后重试处理。您还可以构建一个单独的错误处理流程/视图来处理和处理错误事件。

【讨论】:

    【解决方案2】:

    通常的答案是这样的——我们要做的第一件事是将事件保存在“TODO”列表中。

    我们对该列表的“订阅”需要跟踪,也就是说,写下,它在待办事项列表中的位置。例如,我们可以将 TODO 列表视为仅附加的事件序列,并且订阅会记下最后一个完全处理的事件的索引。

    当订阅运行时,它会在列表中查找第一个未处理的事件,并根据您需要的事务处理工作。完成所有工作后,它会更新自己的计数器(另一个事务),然后继续。

    如果处理失败,那么我们永远不会到达“写下来”这一步;所以当我们重新启动时,它会再次尝试处理相同的事件。

    为此,我们需要两个属性:一个是再次运行处理器应该为聚合生成相同的标识符列表,并且处理器知道聚合可能已经在这种情况下创建并采取适当的行动。

    所以在最坏的情况下:我们用 5 个托盘获得事件。我们创建所有 5 个新聚合,然后在它可以记录事件已完全处理之前崩溃。该过程重新启动,并开始处理同一事件。它发现每个新聚合都已创建,因此这些步骤中的每一个都成为空操作。最后,在完成事件的所有处理后,它记录了事件已经完成。

    换句话说,我们需要幂等处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-11
      • 1970-01-01
      • 2013-01-31
      相关资源
      最近更新 更多