捕获可变实体在域驱动设计中跨上下文引用

时间:2018-01-09 20:09:32

标签: domain-driven-design

当一个上下文中的事件触发事件并且状态通过消息传递更改其他上下文时,如何轻松捕获有界上下文B中的触发事件是由来自A的某些事件以及可能由状态A在某个时间点?

让我们想象以下场景:

  • 您的第一个微服务Account具有聚合根AccountRoot,具有给定ID
  • 您有第二个微服务Customer,其聚合根CustomerRoot,具有给定ID
  • 您有第三个微服务Terms,其聚合根Terms,其中TermsRoot本身就是聚合Proposal的集合,每个聚合都是根据{{1}的实例计算出来的}和Customer的实例。类型为AccountAccountUpdated的事件会触发新的CustomerUpdated

现在您遇到以下问题:

  1. 您需要跟踪用于创建Proposal
  2. 实例的值
  3. 您需要Proposal 幂等:您不希望该处理两次相同Terms,可能是因为AccountUpdated粉碎或{{ 1}}发布两次相同的事件。
  4. 这两个问题导致了这两个问题:

    1. 仅在Terms内存储AccountAccountRoot的ID不起作用,因为它们的状态是可变的。您有两个选择:存储一些时间戳或某种索引,它允许您完全识别CustomerRootProposal的状态(您需要从日记中重建)或存储完整状态,这将使事情变得更容易。但是,这不会污染有界的上下文AccountRoot吗?

    2. CustomerRoot的创建对于TermsProposal的特定状态是幂等的。但是,DDD中的状态没有ID,因此很难确定您是否已创建Customer。我们正在考虑使用某种AccountProposal状态的哈希函数。你是如何解决这个问题的?

2 个答案:

答案 0 :(得分:2)

我从来没有这种需要,但我想我会尝试使用版本控制系统,发布带有事件k = Target_pos.y / cam_pos.y的版本,这样在您的阅读模型中,您可以获得实体的ID和版本产生它。
您可以拥有每个实体的版本,在每个事件中都会增加。

关于发布版本,它将是事件的元数据(与实体的id配对)。

通过事件中的这些信息(以及整个事件历史记录),让一个进程使用您需要的所有数据(关系加上该版本的实体状态)填充读取模型应该不难。

为了使操作具有幂等性,正如您所说,您可以尝试使用输入的哈希值(或输入的一部分)生成id,并检查它是否已存在于生成事件的事件的处理程序中(Account|Customer)Updated

答案 1 :(得分:1)

根据我对您的业务需求的理解,提案不是来自写入方,而是来自读取方的实体,可能由某些TermId分组。

当创建Proposal实体时(通过这两个事件),它使用来自其他两个读取模型的数据:所有帐户的列表和所有客户的列表。从那里它通过ID加载两个读取实体并查询它们以获得所需的状态。在CQRS体系结构中经常可以找到从多个其他读取实体组成读取实体。但是,这会对其他两个读取模型产生依赖关系。此外,如果Read模型需要完全重建,则存在难题。

另一个缓解这些问题的解决方案是,Proposal读取模型维护一个由Account和Customer事件构建的私有独立状态。创建Proposal实体时,将使用此私有状态。该解决方案构建了最具弹性的系统。

请注意,不使用Aggregate,仅涉及Read侧或事件。通过这种方式,Aggregate的封装受到保护。

  

您需要制定术语幂等

     

...

     

但是,DDD中的状态没有ID,因此很难确定您是否已创建提案。我们正在考虑使用某种客户和帐户状态的哈希函数。你是如何解决这个问题的?

您可以通过从两个事件创建时间和Aggregate的ID计算哈希并在持久性上创建唯一索引来实现此目的。

  

但是,这不会污染有界的上下文条款吗?

使用从远程有界上下文生成的事件不会污染本地有界上下文。这是因为这些事件的解释是本地的,它们根据本地上下文规则在本地上下文中起作用。

此外,使用域事件作为集成技术是推荐的方法之一,如果不是最好的话。