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)
我不太关心命令消息,因为用户会立即知道它是否成功.
您可能应该关注命令消息,因为那些实际上会导致记录簿发生变化.是的,快乐的道路很简单,但是当用户的命令未被确认时,您希望用户做什么?
我关心的是事件.如果将聚合版本号附加到事件中,我们是否可以使操作具有幂等性?
请记住,事件来源的entites是从历史记录加载的,而不仅仅是飞过的事件(即订阅).您将从记录簿中加载这些实体,因此您可以获得准确的历史记录.您不必担心事件发生变化,因为它们是不可变的.同样,您不必担心历史记录会发生变化,因为历史记录只会附加.
换句话说,您的事件源实体支持一种apply(Event)方法,您根本不需要保护它,只需按顺序加载事件即可.
同一事物的另一种方式:你的实体的历史是DocumentMessage作为一个序列而不是一个序列传递的EventMessages.
对于从多个事件历史汇总的预测,问题类似.
如果您的实体正在侦听/订阅某些其他实体事件(即您的实体是事件处理器),那么您将需要担心幂等性.请注意,在此用例中,事件有两种不同的上下文 - 事件处理器本身历史中的事件(即描述事件处理器状态更改的事件),以及处理器响应的事件.也就是说,你有apply(Event myStateChanged)vswhen(Event somethingHappenedSomewhereElse)
你不必担心前者的幂等性(见上文); 通过在您自己的历史记录中跟踪该事件,确保您对事件做出一次反应.您的处理器可能是状态机(因此事件自然是幂等的),或者您可以跟踪您订阅的事件的事件ID,然后确保您不会反应多次,等等.
奇怪的是,有些地方会出现"聚合版本" - 它们在命令处理程序中.两种常见形式:首先,命令可能针对要应用的聚合的特定版本(立即解决您的幂等问题); 第二,您将看到跟踪版本号以防止并发修改.