2017-01-24 57 views
0

假设我有一个包含一些数据的聚集,当它达到某个状态时,我想将所有状态传递给一些外部服务。为了说明和简单起见,我们只需说它是一个具有列表的聚合,并且当列表中的所有项目都被选中时,我想将整个状态发送到某个外部服务。现在,当我处理检查列表中最后一项的命令时,我会知道我最后的结果,但从处理命令发送到外部系统似乎不正确。所以在这种情况下,如果外部系统需要聚合的所有状态,那么推荐的方法是什么。外部系统应该根据聚合事件构建自己的数据副本还是有更好的方法?CQRS和传递数据

+0

如果您需要将对象的状态传递给外部服务,为什么不用这个状态创建一个DTO,序列化并将它作为参数传递?我可能错过了什么。 – IlliakaillI

回答

1

外部系统应该根据聚合事件构建自己的数据副本。

可能不是 - 从来没有好的想法来分担从历史中重新补水的责任。拥有物体的服务应该负责补液。

要理解的第一个关键想法是在流程中何时应该发生对外部服务的呼叫。

  1. 首先,域模型处理命令参数,计算对事件历史的更新,包括ChecklistCompleted事件。
  2. 应用程序获取该历史记录并将其保存到记录簿中
  3. 该事务成功完成。

此时,应用程序知道操作成功,但调用者不知道。所以通常的答案是要考虑一个异步操作,它将完成剩下的工作。可能性一:应用程序获取它刚刚保存的历史记录,并使用该历史记录创建调度任务,以重新组合水平状态的只读副本,然后将该状态发送到外部服务。可能性二:你丢弃现在的历史副本,并且启动一个异步任务,该任务有足够的信息从记录本中加载自己的历史记录副本。

至少有三种方法可以做到这一点。首先,你可以让命令像以前一样安排任务。其次,您可以让一个事件处理程序在记录簿中侦听ChecklistCompleted事件,并让该处理程序计划任务。第三,您可以从记录簿中读取ChecklistCompleted事件,并将该事件的表示发布到共享总线,然后让外部服务中的处理程序返回该状态的副本。

我的印象是一个有界的上下文不应该伸手去从另一个有界的上下文获得状态,而是保留它所需要的数据的本地副本。

根据我的经验,关键的想法是服务不应该彼此阻塞 - 或者更具体地说,当服务A不可用时,服务B的呼叫不应该阻塞。对事件的回应基本上是无阻碍的;是否真的很重要,我们通过进行异步阻塞调用来响应异步传递的事件?

这是什么给你买了,但是,这两个服务的独立演进 - A广播事件,B反作用于事件致电A和要求的总的表示是B了解到,A - 是向后兼容 - 提供请求的表示。

将此与每次A中的补液逻辑更改时要求新版本B进行比较。

Udi Dahan提出了一个具有挑战性的想法 - 每一条数据都属于单数的概念technical authority。 “原始业务数据”should not be replicated between services

  • 服务是特定业务能力的技术权威。
  • 任何数据或规则都必须仅由一项服务拥有。

所以在乌迪的做法,你会开始调查为何B具有通过A拥有数据的任何责任,并从那里确定如何使这种责任和数据到一个单一的服务。 (部分诀窍:服务的physical view可以跨越进程边界;换句话说,进程可以由属于多个服务的组件组成)。

杰普克莱蒙series on microservices是很好的来源,并触及上述许多点。

+0

我曾经考虑过可能性,并且不确定,所以我想我会先试一试。你提到了接触外部服务。我的印象是,一个有界的上下文不应该伸手去从另一个有界的上下文中获取状态,而是保留它所需要的数据的本地副本。 –

0

你不应该让你的状态外化。报告该状态是阅读方的一个功能,因为它会生成报告,您需要这些数据来调用服务。你的状态结构是可塑的,你不应该有一个依赖于这个结构的外部服务,否则你将不得不以更新的方式进行更新,这是一件坏事。

There is a blog提出了一个强有力的论点,即流程管理器是放置此类功能(调用外部服务)的正确位置,因为这是编排事件的适当位置。