CQRS/ES - 处理投影错误

CQRS/ES - handling projection errors

我正在研究 CQRS+ES 系统,主要使用轴突框架,但实际上这个问题适用于任何实现。所以我有一个命令处理程序和 1 个或多个事件处理程序,运行 在不同的 JVM、容器等上,并且在某些时候这些处理程序之一遇到错误。

我们有两种情况,'expected' 业务错误和 'unexpected' 系统错误。据我了解,我们现在处于异步处理程序中,事件现在是事实,所以实际上我们不能直接回滚这两种情况的命令(因为它可能需要在许多其他预测中回滚它并破坏 CQRS)。

所以我的问题是,这样的错误应该是 'resolved' 在账户分类账中的某种方式,即通过发送一个新的 'reversal' 命令,然后以这种方式传播到预测失败的事件现在已经解决了吗?

例如,假设我们有一个更新客户信用的命令。该事件已发布,一个投影更新其 "total credits" 统计信息,另一个投影将更新发布到某个 websocket 以获取 UI,最后,另一个保持信用状态 - 最后一个处理程序失败。我们是否应该发送回滚业务交易的命令,再次扣除信用,再次更新 websocket 等?如果是轴突,是否有某种方法可以将其捕获为事务?

我要声明,是否采取行动(从而处理命令)的决定是可以的,应该始终由命令决定 Model/Aggregate。聚合处于处理操作的不正确状态通常会导致 'business exception/error'.

但是,如果您在事件处理失败时做出决定,那么您就是在事件处理服务中添加了一些决策制定逻辑,而在大多数情况下它可能并不关心。它这样的事件处理服务更新 views/query 模型,但没有这样做,我认为这不是将 'compensating command' 发布到 'rollback/undo the event' 的正当理由。

在您的示例中,您有一个 'credit-state-maintainer',我猜它会更新查询模型。因此,我认为处理异常的问题在于服务本身,而不是通过执行补偿操作。

从 Axon 框架的角度来看,您可以将 CreditStateEventHandler 包装在 TrackingEventProcessor 中,并通过调用 TrackingEventProcessor#resetTokens() 函数触发该事件处理器的重置。采取的立场是,您的 CreditStateEventHandler 所导致的异常当然是由于编码错误造成的,否则重播将导致完全相同的异常。