事件来源以及何时进行验证



我正在学习分布式系统中的事件源和CQRS,在试图确定何时是执行验证的最佳时间时遇到了一些困难。。。事件存储之前或之后?我对这个主题进行了大量的搜索和阅读,但似乎找不到解决这个问题的答案/建议。

例如(简单的例子),如果我有一个Web API请求从银行账户提取一些钱,我可能会执行以下验证:

  1. 银行账户存在吗
  2. 银行账户有足够的资金提取吗

当请求到来时,我是在执行上述验证之前保存事件(并有存储无效事件的风险),还是在验证之后保存事件(并且有在过程中出现错误的风险,如服务关闭,而根本不存储事件)?在CQRS的情况下,事件是在命令执行之前存储的,还是作为命令的一部分存储的(在命令处理程序中)?

我很感激在提出请求之前会进行一些验证(例如,要提取的有效金额),但在提出请求前可能无法进行一些验证。

这也导致了我如何在Web API调用的响应中返回错误(例如,银行帐户无效)?

我对这个主题的理解可能完全错误,但正如我之前提到的,我只是在学习这个主题,我希望有人能给出答案,或者能给我指一些帖子/文章,这将有助于我的理解。

来自事件文档:

一般来说,命令处理流程可以这样描述:

  1. 边缘通过其API(HTTP、gRPC、SignalR、消息传递等)接收命令
  2. 它将命令传递给应用程序服务。由于边缘负责身份验证和一些授权,它可以使用用户凭据丰富命令
  3. 命令服务与API本身无关,它处理命令并对边缘做出响应(肯定或否定)
  4. API层然后将响应返回给调用方

在处理一个命令时,命令服务本身执行以下操作:

  1. 如果需要,从命令中提取聚合id
  2. 实例化所有必要的值对象。如果不能构造值对象,这可能会有效地拒绝该命令。命令服务还可以加载一些其他聚合或任何其他信息,这些信息是执行命令所需的,但不会更改状态
  3. 如果命令希望对现有聚合实例进行操作,则会从聚合存储区加载此实例
  4. 使用命令中的值和构造的值对象,对加载的(或新的)聚合执行操作
  5. 聚合要么执行操作并通过生成新事件来更改其状态,要么拒绝操作
  6. 如果操作成功,该服务将新事件持久保存到存储中。否则,它会将失败返回到边缘

我还将分离域模型不变量和验证。我用";验证";当我检查提供的字符串值是否确实是银行账号、有效电话号码、必填字段等时。域不变量,包括聚合不变量(可以处理提款吗)和交叉聚合不变量(一个客户不能有十个以上的银行账户,真的无法想象其他任何东西)。

如果一个给定的帐户不存在,那么为其加载聚合就会失败。然而,聚合本身可以回答以下问题:

  • 给定用户可以从此帐户提取资金吗
  • 帐户是否处于活动状态,未被阻止
  • 提款金额是否在该时间段内允许的提款限额内

根据经验,银行很少关心你在创建付款时账户上是否有钱。它只在付款被执行时才重要,而这几乎从不实时发生。

通常,处理事情的有用方法是将事件定义为处理不会失败的事件(您可以忽略事件来处理它,但它不应该失败)。另一方面,命令可能会失败,或者导致零个或多个事件。

因此,没有对事件的验证,只有对命令的验证。在银行账户示例中,如果可用资金不足,则可能会拒绝提款命令,或者可能导致提款事件和透支事件(例如,如果由此产生的透支金额在保单范围内)。

一个组件的(我故意避免使用"服务"一词)事件可以是另一个组件命令。

顺便说一句,持久化处理可能失败的对象是完全有效的,但这是一种与事件源相关的技术,称为命令源;命令源和事件源通常可以有效地结合在一起,尤其是当命令是其他组件的事件时。

事件是事实陈述,不能更改。它们代表了实际发生的事情。

您可以在命令导致一系列事件之前对其进行验证。

既然你提到了银行账户,很多时候银行不会限制你透支你的账户。他们只是添加了一个新的事实,代表提款产生的透支费。该场景涉及对退出事件的反应,而不是在事件发生之前进行验证。

最新更新