CQRS和传递数据

时间:2017-01-24 00:52:27

标签: cqrs event-sourcing

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

2 个答案:

答案 0 :(得分:1)

  

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

可能不是 - 分享从其历史中补充聚合物的责任几乎从来都不是一个好主意。拥有该对象的服务应该负责补液。

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

  1. 首先,域模型处理命令参数,计算事件历史记录的更新,包括ChecklistCompleted事件。
  2. 应用程序获取该历史记录,并将其保存到记录簿
  3. 交易成功完成。
  4. 此时,应用程序知道操作成功,但调用者没有。所以通常的答案是考虑一个将完成其余工作的异步操作。

    可能性1:应用程序获取刚刚保存的历史记录,并使用该历史记录创建计划任务以重新合并聚合状态的只读副本,然后将该状态发送到外部服务。

    可能性二:你抛弃了现在的历史副本,并启动了一个异步任务,该任务有足够的信息从记录簿中加载自己的历史副本。

    至少有三种方法可以做到这一点。首先,您可以让命令像以前一样安排任务。

    其次,您可以让一个事件处理程序监听记录簿中的ChecklistCompleted事件,并让该处理程序安排该任务。

    第三,您可以从记录簿中读取ChecklistCompleted事件,并将该事件的表示发布到共享总线,并让外部服务中的处理程序回拨您的状态副本

      

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

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

    然而,这给你带来的是两个服务的独立演变 - A广播一个事件,B通过调用A并要求代表事件来对事件作出反应。 B理解的汇总,A - 向后兼容 - 提供所请求的表示。

    将此与每次B中的补液逻辑发生变化时要求新版A进行比较。

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

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

    因此,在Udi的方法中,您开始调查BA所拥有的数据负责的原因,并从那里确定如何协调该责任和数据转化为单一服务。 (部分技巧:服务的physical view可以跨越流程边界;换句话说,流程可以由属于多个服务的组件组成。)

    Jeppe Cramon series on microservices摘得很好,触及上面的许多要点。

答案 1 :(得分:0)

你永远不应该将你的国家外部化。报告该状态是读取方的一个功能,因为它生成报告,您需要该数据来调用服务。你的州的结构是塑料的,你不应该有一个依赖于那个结构的外部服务,否则你将不得不以锁步方式更新这两个是坏事。

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