【问题标题】:How are consistency violations handled in event sourcing?在事件溯源中如何处理一致性冲突?
【发布时间】:2015-12-14 18:49:16
【问题描述】:

首先,让我声明我是命令查询职责分离和事件溯源(消息驱动架构)的新手,但我已经看到了一些显着的设计优势。但是,还有一些我不清楚的问题。

假设我有一个 Customer 类(聚合根),其中包含一个名为 postalAddress 的属性(Address 类的一个实例,它是一个值对象)。我还有一个Order 类(另一个聚合根),它包含(在OrderItem 对象和其他东西中)一个名为deliveryAddress 的属性(也是Address 类的一个实例)和一个名为status 的字符串属性.

客户通过发出PlaceOrder 命令下订单,该命令触发OrderReceived 事件。此时订单状态为"RECEIVED"。订单发货时,仓库有人发出ShipOrder 命令,触发OrderShipped 事件。此时订单状态为"SHIPPED"。

其中一个业务规则是,如果Customer 在订单发货之前更新了他们的postalAddress(即状态仍为"RECEIVED"),则Order 对象的deliveryAddress 也应该被更新。如果Order 的状态已经是"SHIPPED",则deliveryAddress 将不会更新。

问题 1. 将这个“有条件级联地址更新”放在 Saga(又名流程管理器)中的最佳位置是什么?我假设是这样,因为它正在翻译一个事件(“The客户刚刚更新了他们的邮政地址...") 到一个命令 ("... 所以更新订单 123 的送货地址")。

问题 2。如果 Saga 是该工作的正确工具,它如何识别属于用户的订单,因为聚合只能通过它的唯一 ID(在我的例子中是 UUID )?

继续说,鉴于每个聚合代表一个事务边界,如果系统要在 更新Customer 的postalAddress (CustomerAddressUpdated 事件持续到事件存储),但之前 OrderDeliveryAddressUpdated 可以更新(即在两个事务之间),然后系统处于不一致状态。

问题 3。如何检测和纠正这种“违反”一致性规则的行为?

【问题讨论】:

    标签: domain-driven-design cqrs event-sourcing referential-integrity aggregateroot


    【解决方案1】:

    在大多数情况下,订单的送货地址应该独立于任何其他数据更改,因为客户可能希望将订单发送到任意地址。话虽如此,我将给出我的 2c 来说明您如何解决这个问题:

    在流程管理器中处理这个问题的最佳位置是什么?

    是的。你应该有一个OrderProcess。

    鉴于只能通过聚合 id 检索到正确的 OrderProcess 实例,如何获得它?

    没有什么可以阻止人们添加任何将数据关联到聚合 id 的额外查找机制。在我的名为shuttle-recall 的实验性即将上线的机制中,我有一个IKeyStore 机制,它将任意键与AR Id 相关联。因此,您可以将[order-process]:customerId=CID-123; 之类的内容关联为某个聚合的键。

    如何检测和纠正这种“违反”一致性规则的行为?

    在大多数情况下,如果可能的话,它们可以在带外处理。我是否应该从亚马逊订购东西,并且在订单发货后尝试更改我的地址,订单仍会发送到原始地址。如果您将客户邮政地址链接到有效订单地址,您可以通知客户 n 个订单的地址已更新,但最近的订单(在一定的容差范围内)尚未更新。

    至于系统在处理之前出现故障,您应该有一些有保证的交付机制来处理它。我看待这些领域事件的方式与看待服务总线等消息传递基础设施中的系统事件不同。

    只是一些想法:)

    【讨论】:

    • 欣赏这些见解。我在想OrderProcessManager 对象可以提供缓存/索引(客户 UUID 到订单 UUID 向量的映射,用于那些尚未发货的订单,以这种方式是“有状态的”),并且当 @987654329 @ 看到 OrderShipped 事件,它只是从其内部缓存中删除订单 UUID,但是您对存储在事件存储中的任意键/值对与聚合的想法是有见地的。
    • How would one get hold of the correct OrderProcess instance given that it can only be retrieve by aggregate id? 等等...您是说 Process Manager 对象也存储在存储库中(例如,OrderProcess 存储在 OrderProcessRepository 中 - 当然使用 ES )???
    • 拥有OrderProcessRepository 是自定义实现世界中的一个选项。如果您使用 C#,我在 samples for my service bus 文件夹下的 Shuttle.ProcessManagement 中有 3 个进程管理器的实现。要点是您将要知道一些数据,例如客户编号。在处理创建初始流的代码中,您应该有权访问该数据,并且在 点您将创建 AR Id 和任意键之间的关联。
    • 实现的查询端也可以包含该关联,因此您可能不需要像IKeyStore 这样的东西。但是,如果您可以,例如,每个客户只有一个有效订单(愚蠢,但仅作为示例),您可以使用密钥存储来确定是否存在有效的密钥/ID 关联以防止重复。
    • 感谢您的意见。还在琢磨想法。你介意分享你对这个问题的想法吗:stackoverflow.com/questions/34250464/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 2018-01-16
    • 2019-02-20
    • 1970-01-01
    相关资源
    最近更新 更多