如何在基于CQRS和DDD的应用中使用补偿措施

时间:2017-10-04 13:06:01

标签: validation domain-driven-design cqrs eventual-consistency

我们假设我们托管了两个微服务:RealEstateCandidate

  • RealEstate服务负责管理租赁物业,房东等。
  • Candidate服务提供申请出租物业的命令。

会有一个CandidateForRentalProperty命令需要RentalPropertyId和所有必要的Candidate信息。

现在关键点:不同类型的RentalProperty需要一组不同的Candidate信息。

因此,命令和聚合被拆分了:

  • 命令:CandidateForParkingLotCandidateForFlat,等等。
  • 汇总:ParkingLotCandidatureFlatCandidature,等等。

UI要求读取模型决定必须调用哪个命令。

我可以在Candidate域图层中验证Candidate信息及其所涉及的所有业务逻辑,但是无法验证是否获得了正确的命令根据给定的RentalPropertyId 进行调用。 原因:此验证涉及多个聚合。

微服务应该自主,并且它的读取模型会消耗来自RealEstate域的事件,因此它不能保证是最新的。我们不想基于此拒绝候选人,而是使用最终一致性

是的,这可能导致用于某种Candidate的无效RentalProperty信息。有人可以使用停车场出租物业ID来调用CandidateForFlat命令。

但我们如何处理发生这种情况的案件? RealEstate域名对Candidate s。

一无所知

是否会有一个事件处理程序检查是否有错误并执行适当的命令来补偿?

另一方面,这个"映射"是域逻辑,我想在域层中容纳它。但我不知道谁对这种补偿措施负责。 Candidate汇总是否会被通知,例如IneptApplicationTypeUsed或类似的东西?

3 个答案:

答案 0 :(得分:0)

作为旁白 - 命令通常是命令式动词。 ApplyForFlat可能是比CandidateForFlat更好的拼写。

你可能在这里寻找的模式是exception report;当候选服务与具有ParkingLot标识符的CandidateForFlat消息匹配时,候选服务作为输出发出一条消息,说“嘿,我们在这里遇到了问题”。

如果跟进消息解决了问题 - 候选服务获取更新的消息,该消息修复CandidateForFlat消息中的标识符,或候选服务从房地产获取更新,宣布标识符实际指向Flat,则候选服务可以发出另一条消息“没关系,问题已得到修复”

我倾向于在这种模式中发现服务的输入命令实际上只是handle(Event)的变体;用户已提交,http请求已到达;唯一的问题是微服务是否选择跟踪该事件。换句话说,“命令”流只是微服务订阅的另一个逻辑事件源。

答案 1 :(得分:0)

正如您所说,命令验证应该在命令生成点执行 - 在客户端 - 可以读取模型。

命令处理由聚合执行,因此它不能也不应该检查其他聚合的有效性或存在性。所以它应该信任命令发行者。

如果命令来自不受信任的环境(如公共API),则您的API网关将成为客户端,并且它应具有必要的读取模型来验证引用。

如果要快速接受命令并稍后检查,则记录ClientAppliedForParkingLot等事件,并通过保持其内部状态并发出诸如AcceptApplication或RejectApplication之类的命令来使Saga/Process manager处理进一步的工作流。

答案 2 :(得分:0)

我理解验证的必要性,但我不认为您给出的示例要求交叉聚合(或交叉微服务)补偿措施,如Q标题所述

验证,例如检查客户提供的ID以及公寓租赁命令是否与公寓相匹配,而不是停车场,客户有权这样做,等等是合法的。但是让客户端在野外创建这样的命令并等待外部参与者来执行这些规则似乎不合理,因为规则可以是发起进程的对象的内在属性

所以我建议将入口点更改为操作 - 在another Aggregate Root's behavior中创建Candidature聚合根。如果其他聚合(在我们的例子中为RentalProperty)存在于另一个有界上下文/微服务中,则可以在Candidate有界上下文中维护一个RentalProperties列表,只需要所需的信息量,然后启动{ {1}}从那里开始。

所以你会有

Candidature == loading ==> FlatCandidatureHandler ==创建==> RentalProperty

FlatCandidature ==检查存在==> FlatCandidatureHandler

==创建==> local RentalProperty data

作为旁注,实际上需要补偿行动的因素是过程根本对象的外在因素。例如,如果该属性在同一时间内变得不可用。然后无论Aggregate认为信息应该在发生事件时发出事件并且应该启动补偿。