CQRS 如何获取聚合最终版本?

CQRS How to get aggregates final version?

假设您有一个命令可能会在聚合上生成多个事件。您如何确定最终版本实际上是什么?因此,在您知道所有事件都已处理之前,您不会从读取模型中获取它。

ServiceLocator.CommandBus.Send(new SomeCommand(..., currentVersion));

使用命令总线,我看不出有什么明显的方法可以获取 return 说明新聚合版本的值。

建议?

据我所知

  1. 你的方向完全正确
  2. 是的,命令总线挡住了你的路

由于命令总线不允许你传回你想要的信息,你必须向前传递它,然后查询它。 command handler把你想要的信息写在某处,你在得到command完成的信号后查询。

换句话说,您可以将应用程序本身视为一种抽象,您向它发送命令,命令更新版本号,然后您查询这些版本号。这种抽象已被拆分为单独的职责——命令职责通过命令总线实现,查询职责由……好吧,这就是需要解决的问题。

你的每条命令消息都应该有一个唯一的标识符(无论如何你都会想要类似幂等的东西)。事件成功保存后,命令处理程序将新版本号写入键值存储,使用命令 id 作为键。

在您的呼叫者中,您将阻塞直到该条目可用;然后从商店阅读并继续。

不是我最喜欢的选择,但它并没有真正违反我们所教的任何 good/successful 设计原则。

例如,Gregor Hohpe 谈到使用 correlation identifier 来协调请求消息和回复消息。在此示例中,请求将是带有其标识符的命令,而回复将是一条描述流的新高水位标记的消息。

例如,您可能会想象应用程序获取事件源实体的新事件列表,保存它们,然后发布一个新事件说 "the stream is now at version 12345"。您的代码在提交命令消息后会一直阻塞,直到高水位消息到达。

(如果消息没有在合理的时间内出现?重新发送命令!我们确保命令是幂等的,所以这将是一个选项。)

另一种可能性:也许您根本不需要知道高水位线;毕竟,您拥有命令 ID。如果命令保留的事件有一个因果标识符(意思是,每个事件都用产生它的命令的 ID 标记),并且您相信事件历史是自动保存的,那么......将查询与命令;当命令完成时,"redirect" 到查询,传递命令标识符,并让查询阻塞,直到至少一条具有正确命令 ID 的消息出现在历史记录中。

老实说,这和以前的行为是一样的,只是把阻塞放在了不同的地方。

另一种可能性是客户端自己跟踪版本。粗略的想法是,即使记录簿受服务器保护,客户端也可以拥有自己的模型副本,以及它关心的对象的缓存。客户端在本地运行命令以确保它不会弄脏任何东西,然后将命令发送到服务器——如果命令成功,已经知道答案将是什么。

将其视为另一种形式的乐观并发。