使用事件源时,使用聚合版本号是幂等的

mag*_*nus 2 domain-driven-design idempotent cqrs event-sourcing

使用DDD,CQRS和事件源时,可能会重新发送消息或无序发送消息.

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

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

Voi*_*son 7

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

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

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

请记住,事件来源的entites是从历史记录加载的,而不仅仅是飞过的事件(即订阅).您将从记录簿中加载这些实体,因此您可以获得准确的历史记录.您不必担心事件发生变化,因为它们是不可变的.同样,您不必担心历史记录会发生变化,因为历史记录只会附加.

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

同一事物的另一种方式:你的实体的历史是DocumentMessage作为一个序列而不是一个序列传递的EventMessages.

对于从多个事件历史汇总的预测,问题类似.

如果您的实体正在侦听/订阅某些其他实体事件(即您的实体是事件处理器),那么您将需要担心幂等性.请注意,在此用例中,事件有两种不同的上下文 - 事件处理器本身历史中的事件(即描述事件处理器状态更改的事件),以及处理器响应的事件.也就是说,你有apply(Event myStateChanged)vswhen(Event somethingHappenedSomewhereElse)

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

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