为什么将命令和事件限制为一个集合? CQRS + ES + DDD [英] Why limit commands and events to one aggregate? CQRS + ES + DDD

查看:81
本文介绍了为什么将命令和事件限制为一个集合? CQRS + ES + DDD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请说明为什么在进行CQRS,ES和DDD时同时修改多个聚合是一个坏主意。

Please explain why modifying many aggregates at the same time is a bad idea when doing CQRS, ES and DDD. Is there any situations where it still could be ok?

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

Take for example a command such as PurgeAllCompletedTodos. I want this command to lead to one event that update the state of each completed Todo-aggregate by setting IsActive to false.

为什么这样做不好?

我能想到的一个原因:

在更新域状态时,最好将交易限制在定义明确的部分整个状态,因此在更新期间仅此部分需要写锁定。这样做将允许在不同聚合上并行执行许多写入操作,这可以在某些极端繁重的情况下提高性能。

When updating the domain state it's probably good to limit the transaction to a well defined part of the entire state so that only this part need to be write locked during the update. Doing so would allow many writes on different aggregates in parallell which could boost performance in some extremely heavy scenarios.

推荐答案

问题在于集合的含义。

The response of the question lie in the meaning of "aggregate".

首先,我要说的不是修改‘n’聚合,而是修改‘n’实体。

As first thing I would say that you are not modifying 'n' aggregates, but you are modifying 'n' entities.

集合包含一个以上的实体,它只是一个 transaction 概念,在需要时使用集合(模式)事务性地修改应用程序中多个实体的状态(全部修改或不修改)。

An aggregate contains more-than-one entity and it is just a transaction concept, the aggregate (pattern) is used when you need to modify the state of more than one entity in your application transactionally (all are modified or none).

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

Now, why you would modify more than one aggregate with one command?

如果您认为有此需要,请在进行其他操作之前检查聚合边界,以查看是否可以对其进行修改以消除对1命令->’n’聚合的需求。

If you feel this needs, before doing anything else check your aggregate boundaries to see if you can modify it to remove the needs to 1 command -> 'n' aggregate.

一个聚合可以包含很多相同类型的实体,因此对于您的命令 PurgeAllCompletedTodos ,您还可以考虑扩大交易范围从单个 Todo 到包含所有用户待办事项的汇总 UserTodosAggregate ,并让它管理单个用户待办事项的所有命令。

这样,您可以在一次交易中修改用户的所有待办事项。

An aggregate can contains a lot of entities of the same type, so for your command PurgeAllCompletedTodos, you could also think about expand the transaction boundary from a single Todo to an aggregate UserTodosAggregate that contains all the user todos, and let it manage all the commands for the todos of a single user.
In this way you can modify all the todos of a user in a single transaction.

如果仍然不能解决您的问题,因为,清除应用程序中每个用户的所有已完成待办事项,您仍然需要向 n个聚合发送命令,聚合边界无济于事,因此我们可以考虑使用 AllApplicationTodosAggregate 来管理

可能这不是最好的解决方案,因为正如您所说的那样,该命令将阻止应用程序的所有待办事项,但是请始终检查它是否可以作为一个很好的选择。 f(DDD的《蓝皮书》和《红皮书》都很好地解释了阻塞的这一部分)。

If this still doesn't solve your problem because, let's say that is needed to purge all completed todos of each user in the application, you will still need to send a command to 'n' aggregates, the aggregate boundary doesn't help, so we can think of having an AllApplicationTodosAggregate that manage the command.
Probably this isn't the best solution, because as you said it that command would block ALL the todos of the application, but, always check if it can be a good trade off (this part of the blocking is explained very well in both Blue Book and Red Book of DDD).

如果我需要修改某些实体而又不能将它们汇总在一起怎么办?

What if I need to modify some entities and can't have them in a single aggregate?

如前所述,由于事务的缘故,修改多个聚合的命令是不好的。如果您修改3聚合,首先是好的,然后关闭服务器怎么办?

With the previous said, a command that modify more than one aggregate is bad because of transactions. What if you modify 3 aggregate, the first is good, and then the server is shut down?

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

In this case what you are doing is having a lot of single modification that needs to be managed to prevent inconsistency of the system. It can be done using a process manager, whom responsabilities are modify all the aggregates sending them the right command and manage failures if they happen.

聚合仍然接收它自己的命令,但是流程管理器负责以已知的方式发送它们(一次,一次并行,每次5次) ,您想做什么)

因此,您可以制定一种策略来管理两个事务之间的失败,并做出类似以下的决定:如果失败,请回滚直到现在为止所做的所有修改(向每个聚合发送回滚命令),或者如果操作失败,则每30分钟重复3次,如果不起作用则回滚,如果失败,则为系统管理员创建通知。

An aggregate still receive it's own command, but the process manager is in charge to send them in a way it knows (one at time, all in parallel, 5 per time, what-do-you-want)
So you can have a strategy to manage the failure between two transaction, and make decision like: "if something fail, roll back all the modification done untill now" (sending a rollback command to each aggregate), or "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".

(很长的帖子,很抱歉,至少希望对您有所帮助)

(sorry for the long post, at least hope it helps)

这篇关于为什么将命令和事件限制为一个集合? CQRS + ES + DDD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆