Java 应用程序中的 Axon - 对事件处理程序错误做出反应

Axon in Java app - reacting to event handler errors

抱歉,如果这已经被涵盖,我是 Axon 的新手,我相信我已经阅读了相关的 Axon 文档并浏览了问题,但没有找到任何涵盖我的问题的内容。

这是我的查询...

使用 Axon,我知道我可以创建命令,将其发送到网关,然后将其转发到正确的聚合,然后 应用 一两个事件。然后,事件会被持久化,并可选择传递给 other 事件处理程序。

(请注意,在我的例子中,我使用的是 Spring 引导,带有 EmbeddedEventStoreSimpleCommandBusJdbcEventStorageEngine)。

对于 Axon 4,我注意到额外的 EventHandlers 正在与处理命令的线程不同的线程中执行,因此大概期望命令已成功完成一次聚合的命令处理程序方法已应用事件 (?)

我的问题真正归结为:使用 Axon 的系统如何(或应该)处理这些下游事件处理程序中的错误?

例如,下游处理程序可能会调用另一个 API - 如果该请求失败应该发生什么,Axon 是否有任何内置的东西为此提供了良好的约定?

在基于 non-CQRS/Axon 的应用程序中,我想这主要是通过使用外部消息总线来托管 event 消息并根据新消息触发消费者来执行的. XA 事务可用于确保数据一致性(例如,将数据写入数据库,将消息添加到队列)。我不确定 XA 事务是否仍被广泛接受 - 考虑到微服务如何变得更加突出。

对于 Axon,我怀疑命令已成功完成,即使其中一个下游事件处理程序失败。我了解 Axon 正试图将这两个问题完全分开。

可能的解决方案...?

我可以引入一个外部消息总线或数据库来存储失败的事件并重试它们,但我不禁认为这是在重复 Axon 已经在做的事情——存储事件和执行代码以响应事件。序列化一个事件,发送到一个队列(也可能会失败),只是为了它被消费,然后在应用程序中重新播放,这似乎需要做很多工作。我不确定如何重新调用相同的处理程序,即使我将相同的事件反序列化为 EventMessage.

有人对此有什么想法吗? 也许我完全忽略了 CQRS 和 Axon 的要点,并且以错误的方式处理事情。如果是这样,请更正 :).

谢谢

我不确定是否正确理解你的问题。

My question really comes down to: how do (or should) systems using Axon handle errors in these downstream event handlers?

下游事件处理程序(我假设一个单独的 class 实现一个或多个 @EventHandler 方法)在注释方法正常终止后立即将事件标记为“已消耗”。如果在方法执行过程中抛出异常,则认为该事件未被消费。如果配置为使用持久令牌存储​​,Axon 会跟踪已处理的事件,并在先前通过 EventHandler 方法处理事件的请求失败时重试。它会不断尝试,直到最终被消耗掉。

With Axon, I understand that I can create a command, send it to the gateway, it then forwards it to the correct Aggregate, which then applies an event or two. The events are then persisted and optionally passed on to other event handlers.

如果您的意思是 'the events are then persisted' 当调用 AggregateLifecycle.apply 方法并将事件作为参数传递时,事件会持续存在,那么您是对的。然后该事件将保存在其他线程正在“扫描”以通知 @EventHanlder 注释方法的事件存储中。

With Axon 4, I'm noticing that additional EventHandlers are being executed in a different thread to the one which handles the command, so presumably there is an expectation that the command has been completed successfully once the Aggregate's command handler method has applied the events (?)

正确!请记住,虽然命令是“即发即弃”。它们不存储在某种命令存储中。如果命令处理程序由于某种原因无法完成或失败,那就糟糕了......应该通过发送新命令来重试。命令是对聚合执行一些状态更改操作但从不更改状态本身的请求。由聚合根据其当前状态决定是否允许此状态更新。如果是这样,则聚合发出一个事件信号,该事件将存储在事件存储中。该事件将再次被更新状态的聚合 @EventSourcingHandler 捕获。如果请求无效,则不会应用任何事件,并且命令方法只是正常终止而忘记了曾经发送过的命令。

希望这能澄清您的一些问题。