每个命令都有事件源补水功能吗?

时间:2018-07-25 18:04:00

标签: architecture domain-driven-design cqrs event-sourcing aggregateroot

我有一个事件源系统,并辅以CQRS模式。 假设该命令有效,则发给服务器的每个命令都将使用事件流将我的聚合(新初始化的聚合)重新混合到当前状态。

我的问题是-为什么我应该在每个命令中重新填充聚合状态?为什么我不能只为每个聚合ID保留一个聚合实例,而不必担心重新补水每个命令?在这种情况下,我只会在启动服务器时重新补充事件。

这样做有什么问题吗?由于事件继续存在,因此它仍将保留状态历史。

谢谢!

编辑:我每n个事件都会快照一次聚合状态,因此每次重新补水时我不必重新补水n个事件。此外,每次保存新快照时,我都会缓存聚合状态以保存对该状态的请求。 我更想知道,如果我只想将一个正在运行的聚合实例保留在内存中(按aggregateId),为什么还要重新补水

2 个答案:

答案 0 :(得分:3)

  

为什么我不能只为每个聚合ID保留一个聚合实例,而不必担心为每个命令重新加水?

当然,这很好-您可以通过缓存表示内存中的聚合来节省一些工作。

如果您拥有多个可以更改事件流的进程,则会变得越来越困难;您需要做一些额外的记账工作,以防止当本地缓存的副本恰巧与最新编辑不同步时,您不会错误地计算事件。

答案 1 :(得分:2)

在几乎所有情况下(从个人经验来看),我都同意@voiceofunreason的观点,即存储/缓存“当前”聚合状态非常好。但是,您应该意识到这样做可能会丢失某些东西:

  1. 您没有锻炼骨料的水分。这可能会使版本控制问题隐藏足够长的时间,从而成为一个大问题。可以认为这与备份数据库类似,但是从不测试还原。
  2. 通过存储高速缓存,您失去了使用延迟事件的机会。例如,您可能有一个类似“ 11月之后适用新价格”的事件。拥有该事件后,您将对其进行存储,但是它只会在特定日期之后影响状态(定价)。诚然,这是一种特定的(当然也不是很常见)的情况,但这是您将要失去的东西。
  3. 您将无法进行(双向)时间查询,例如“我当时对X的了解是什么”。

要点1比其他要点更重要,但是实际上每次都可以通过这种方法来补充水分。只是在许多情况下补液是个不错的选择。

在事件旁边使用快照,并使用快照+较新的事件补液可解决这些问题,因为:

  1. 重新构建 直到进行快照为止
  2. 当您遇到“后期触发事件”时,由于快照是与事件并排存储的,因此很容易在应用延迟触发事件之前停止快照,然后再进行快照即可。
  3. 您可以绕过快照以进行临时查询。