为什么将命令和事件限制为一个聚合? CQRS + ES + DDD

Why limit commands and events to one aggregate? CQRS + ES + DDD

请解释为什么在执行 CQRS、ES 和 DDD 时同时修改许多聚合不是一个好主意。有没有什么情况还可以的?

以诸如 PurgeAllCompletedTodos 之类的命令为例。我希望此命令引发一个事件,通过将 IsActive 设置为 false 来更新每个已完成的待办事项聚合的状态。

为什么这样不好?

我能想到的一个原因:

更新域状态时,最好将事务限制在整个状态的明确定义的部分,以便在更新期间只需要对这部分进行写锁定。这样做将允许在不同的聚合上并行写入许多内容,这可以在一些极其繁重的场景中提高性能。

问题的答案在于"aggregate"的意思。

首先我要说的是,您不是在修改 'n' 聚合,而是在修改 'n' 实体。

聚合包含多个实体,它只是一个事务的概念,当需要修改多个实体的状态时使用聚合(模式) entity 在您的应用程序中进行交易(全部修改或 none)。

现在,为什么要用一个命令修改多个集合?

如果您觉得有此需求,请在执行任何其他操作之前检查您的聚合边界,看看是否可以修改它以消除对 1 个命令 -> 'n' 聚合的需求。

聚合可以包含许多相同类型的实体,因此对于您的命令 PurgeAllCompletedTodos,您还可以考虑从单个 Todo 到包含所有用户待办事项的聚合 UserTodosAggregate,并让它管理单个用户的待办事项的所有命令。
通过这种方式,您可以在单个事务中修改用户的所有待办事项。

如果这仍然不能解决您的问题,假设需要清除应用程序中每个用户的所有已完成待办事项,您仍然需要向 'n' 聚合发送命令,聚合边界没有帮助,所以我们可以考虑使用 AllApplicationTodosAggregate 来管理命令。
可能这不是最好的解决方案,因为正如您所说,该命令会阻止应用程序的所有待办事项,但是,请始终检查它是否是一个很好的折衷方案(这部分阻止在 Blue 中得到了很好的解释DDD 的书和红皮书)。

如果我需要修改一些实体但不能将它们放在一个聚合中怎么办?

如前所述,由于事务的原因,修改多个聚合的命令是错误的。如果修改3个聚合,第一个好,然后服务器关了怎么办?

在这种情况下,您正在做的是进行大量需要管理的单一修改,以防止系统不一致。 这可以使用流程管理器来完成,流程管理器的职责是修改所有聚合,向它们发送正确的命令并在发生故障时进行管理。

聚合仍然接收它自己的命令,但进程管理器负责以它知道的方式发送它们(一次一个,所有并行,每次 5 个,你想要什么)
所以你可以有一个策略来管理两个事务之间的失败,并做出如下决定:"if something fail, roll back all the modification done untill now"(向每个聚合发送回滚命令),或 "if an operation fail repeat it 3 times each 30 minutes and if doens't work then rollback"、"if something fail create a notification for the system admin".

(抱歉这么长 post,至少希望对你有所帮助)