【问题标题】:Using aggregate version numbers to be idempotent when using event sourcing使用事件溯源时使用聚合版本号是幂等的
【发布时间】:2016-05-16 05:26:52
【问题描述】:

使用 DDD、CQRS 和事件溯源时,可能会重新发送消息或乱序发送消息。

我不太关心命令消息,因为用户会立即知道它是否成功。我关心的是事件。如果将聚合版本号附加到事件中,我们可以使操作幂等吗?例如:

class Person {
    public function apply(PersonNameUpdated event) {
        if (version_ + 1 != event.version) {
            name_ = event.name;
            ++version_;
        }
    }
    private String name_;
    private Integer version_;
}

【问题讨论】:

  • 从您的事件存储中读取事件时,它们应该已经按照正确的顺序以及正确的版本号。在这种情况下,这种检查不是多余的吗?也许您可以扩展您所面临的问题。

标签: domain-driven-design cqrs event-sourcing idempotent


【解决方案1】:

我不太关心命令消息,因为用户会立即知道它是否成功。

您可能应该关注命令消息,因为这些消息实际上会导致记录簿发生变化。是的,快乐的道路很容易,但是当用户的命令未被确认时,您希望用户做什么?

我关心的是事件。如果将聚合版本号附加到事件中,我们可以使操作幂等吗?

请记住,事件源实体是从历史中加载的,而不仅仅是经过的事件(即订阅)。您将从记录簿中加载这些实体,因此您可以使用确切的历史记录。您不必担心事件会发生变化,因为它们是不可变的。同样,您不必担心历史记录会发生变化,因为历史记录只是追加的。

换句话说,您的事件源实体支持apply(Event) 方法,您根本不需要保护它,您只需按顺序加载事件即可。

同样的事情的另一种方式:您的实体的历史以DocumentMessage 的形式提供,而不是EventMessages 的序列。

对于从多个事件历史中收集的预测,这些问题是相似的。

如果您的实体正在侦听/订阅一些其他实体事件(即,您的实体是事件处理器),那么您将需要担心幂等性。请注意,在这个用例中,事件有两种不同的上下文——事件处理器本身历史中的事件(即描述事件处理器状态变化的事件)和处理器正在响应的事件.也就是说,你有apply(Event myStateChanged) vs when(Event somethingHappenedSomewhereElse)

您无需担心前者的幂等性(见上文);您通过在您自己的历史记录中跟踪该事件来确保您对某个事件反应一次。您的处理器可能是一个状态机(因此事件自然是幂等的),或者您可以跟踪您订阅的事件的事件 ID,然后确保您不会多次做出反应,等等。

奇怪的是,有些地方确实出现了“聚合的版本”——它们在命令处理程序中。两种常见形式:首先,命令可能针对要应用的特定版本的聚合(立即解决您的幂等问题);其次,您将看到版本号跟踪以防止并发修改。

【讨论】:

    猜你喜欢
    • 2019-07-16
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多