来自外部系统的事件采购命令或事件?

时间:2012-08-09 16:39:40

标签: cqrs event-sourcing

在大多数情况下,我理解命令与CQRS + ES系统中的事件之间的区别。但是,有一种情况我无法弄清楚。

假设我正在构建个人财务跟踪系统,用户可以在其中输入借方/贷方。显然这些是命令,一旦验证它们,域模型就会更新并发布一个事件。但是,假设信用/借记信息也直接来自外部系统,例如用户的花店发送一条消息,表明他已经向用户的信用卡收取了他的定期母亲节交付费用。在这种情况下,消息似乎是一个事件(已经发生了收费),但消息可能格式错误并且将被拒绝。它真的是一个命令吗?但是后来需要一种方法来发送ACK / NACK,这不是这里的情况(花店只有在知道借记已经发生时才发送消息)。

编辑:只是为了澄清,我不是在谈论外部系统对我的事件和/或命令的了解。我有一个组件从外部系统接收数据,然后必须发布事件或发送命令。问题是,我的组件应该使用哪个事件或命令?

2 个答案:

答案 0 :(得分:11)

这是有界上下文的完美示例。

在代表相同或业务流程步骤的另一个系统(或有界上下文)中发生的事件不应被视为接收系统中发生的事件。

Florist系统借记事件的结构可能与财务跟踪系统中可能发生的借方事件不同。

为了解决这个问题,我会有一个会听取花店系统事件的终点,我会根据事件中的信息让财务跟踪系统发出命令,并将其与财务跟踪系统中的信息结合起来。如果需要的话。如果发生这种情况,可以将其视为财务跟踪系统的客户,或者如果您愿意,甚至可以将其视为“域名服务”。

在这种特殊情况下,来自Florist系统的事件会提供Florist系统中发生的交易信息(有界上下文)。我不会在域服务中做出任何决定,而是向财务跟踪系统域发出命令,在该域中进行决策并发布财务跟踪系统事件。如果Florist系统事件在财务跟踪系统中显示格式不正确,您可能不希望以请求/响应或Ack / Nack方式告知Florist系统。该活动是从花店发布的,如果你实现类似的东西,你会打破消息模式。您的消息传递基础结构应该允许您重试消息,甚至修复接收代码,并使用新代码重试消息。

但是,如果您确实需要与Florist有限的上下文进行沟通,Florist系统可以订阅来自财务跟踪系统的事件,以确定交易是否已成功处理。只有在主系统决定是否可能发生交易时才需要这样做。

如果您描述财务跟踪系统更像是一个交易日志,您唯一需要做的就是不将Florist事件视为财务跟踪系统事件。在介于导致财务跟踪系统事件的命令之间加入一些东西。

编辑:

作为对您的修改的回复。您接收组件应该向财务跟踪系统域发送命令,而财务跟踪系统域又会发出事件(像往常一样)。

答案 1 :(得分:2)

我在想知道同样的事情时发现了这个问题。

我喜欢Mikael的回答并对其进行了褒奖。但是,我在DDD / CQRS论坛上找到了另一个采用不同方法的答案,因此我想把它发布在其他正在寻找的人身上。

Here's a quote from Greg Young关于跟踪外部状态的类似问题:

  

在大多数库存系统中,没有命令。

或者解释:

  

专门跟踪外部状态的系统将没有命令。

让我们回过头来思考一下你的系统如何根据这个想法发展(让我们假设你不是为自己构建它):

  • 您决定创建一个个人财务跟踪器,记录来自外部世界的交易,显示图表,汇总总数等。
  • 因为事件是用于跟踪状态更改而不是命令,所以您可以记录这些更改。您还可以在事件处理程序中编写投影,以将事件聚合为总计和图形数据点。
  • 然后你会得到用户。他们称赞应用程序,但使用率仍然很低。深入挖掘之后,您会发现他们仍然使用其他应用来跟踪财务状况,例如,当地卡片商店没有针对重复出现的母亲节贺卡的API,他们希望"拆分&# 34;一个外部交易成多个,他们的银行没有在线访问,他们想跟踪现金等。
  • 因此您添加了用户输入的交易。您可以通过添加跟踪用户输入的事务的命令来执行此操作。现在,我们与您的问题处于同一系统。

请注意,此变体同时接受命令和事件。您不会返回并将所有现有事件转换为命令,因为您现在允许用户更改内容。相反,您有一个系统接受外部事务事件,用户输入事务的命令和事务更正(创建修改内部状态的事件),以及组合这些内部和外部事件以进行显示的投影应用程序。

我很好奇。事后看来,接受的答案最终是一个好方法吗?或者像Greg一样直接记录和处理花店的事件会更好吗?