事件验证

Event validation

我们正在考虑在工作中实施 CQRS 模式,并且有几个关于验证的问题。

假设我们有 3 个聚合根:

当用户注册时,发送的事件将是:

UserCreated
BusinessCreated
UserAddedToBusiness

需要验证事件,例如要在用户和企业之间创建 link 用户和企业都应该创建。

我看到两种方法。

  1. 前期验证:使用上次处理的快照加上未处理的事件动态构建读取模型并将其用于验证。

  2. 处理时验证:按原样接受 events/commands 并在处理事件时进行验证。

第一种方法有即时反馈,但它需要创建最终读取模型以进行验证。第二个更简单,但不会向消费者提供出错的反馈。

我在想这样的事情:当你发出一个事件时,你会得到一个 id,你以后可以用它来查询事件的状态。如果事件处理成功,你会得到 'OK',否则你会得到一个错误,告诉你出了什么问题。

这是一种有效的方法还是矫枉过正?消费者如何知道事件已被处理并且数据已准备好使用?

问得好 Leonti - 您可能会发现我关于在 CQRS 系统中进行验证的博客 post 很有帮助。你可以在这里找到它:How To Validate Commands in a CQRS Application

从标题中可以看出,CQRS 的重点是验证命令而不是事件。

为什么?

因为命令可能来自用户输入,因此不应被信任。 另一方面,事件是从域内发出的并且可以被信任。可能存在 CQRS 的实现,其中涉及离开系统边界的事件或接收并非源自系统内部的事件。在这些边缘情况下,应该小心。

另一个潜在的危险信号是您描述聚合的方式。在我看来(我不知道你的域,所以不能 100% 确定)它们更类似于数据库中的表而不是聚合。重要的是不要让你的持久化机制支配你的模型。

更具体地回到你的问题。

从广义上讲,有两种类型的验证。浅而深。肤浅的是缺少字段、有效的电子邮件地址等。深度是领域概念发挥作用的时候。例如需要货物的重量和表面验证,但货物是否适合承运人可能是一个领域概念。

您可能需要验证 things.e.g 是否存在。是否存在企业或用户。虽然这种验证很可能需要您访问数据库,但它仍然是肤浅的,因为它不太可能是一个明确的领域概念。

无论如何,希望对您有所帮助。

这里主要有两个方面:

  1. 在 CQRS 中,您可以使用命令和查询。事件来自哪里?假设您还指的是事件源,那么在使用命令时,您仍然会在客户端进行一些验证,一些在命令处理程序中进行,一些在域模型中进行(聚合不变量和约束)。这个特定的例子看起来像是在客户端和命令处理程序内部验证的东西。

  2. 请记住,由于您在三个不同的聚合上有三个不同的操作,因此您需要三个事务。这意味着,如果其中一个无法完成 - 您的系统将进入无效状态。您要么需要重新考虑聚合边界以获得一个聚合根,要么考虑使用其他技术,例如事件驱动策略、sagas(流程管理器)或路由单(sagas)。

当然,UserToBusinessRelationship 听起来更像是多对多 RDBMS link table 而不是聚合,但我对您的域一无所知。