在同一 spring 引导应用程序中多次侦听同一事件时处理轴突中的异常

Handling exceptions in axon when listening to the same event multiple times in same spring boot application

我们正在将 Axon 集成到我们现有的 spring 启动应用程序中。我们目前正在使用 Axon 4.1.2 和 Axon Server。

例如在注册过程中,我们触发一个 RegisterCommand,它被 RegisterAggregate 读取并触发 RegistrationDoneEvent

有两个EventHandlers在听这个RegistrationDoneEventRegistrationNeo4jEventHandlerRegistrationSqlEventHandler.

没有异常时一切正常。但是,当出现异常时,假设 Neo4JEventHandler 接收到事件,如果出现异常,则 SqlEventHandler 窗台被调用,似乎一切仍在 SqlEventHandler 上回滚即使 SqlEventHandler 运行 成功。

我们怎样才能使 SqlEventHandler 完成并提交但 Neo4JEventHandler 重试?

其次,我们如何在失败时完全停止重试事件?假设我们有四个事件处理程序(HandlerA、HandlerB、HandlerC、HandlerD)监听 SAME 事件。如果 HandlerC 失败,我们希望在我们假设解决了潜在问题时触发它重试,但还要确保不会重新运行侦听 SAME 事件的其他处理程序。

以下代码片段包括聚合和事件处理程序。

RegisterAggregate

@Aggregate
public class RegisterAggregate {

    ....

    @CommandHandler
    public RegisterAggregate(RegisterCommand command) {
        apply(new RegistrationDoneEvent(command));
    }
}

RegistrationSqlEventHandler

@Service
@Transactional
public class RegistrationSqlEventHandler { 

    @EventHandler
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public void on(RegistrationDoneEvent event) {
        ....
    }
}

RegistrationNeo4jEventHandler

@Service
@Transactional
public class RegistrationNeo4jEventHandler { 

    @EventHandler
    public void on(RegistrationDoneEvent event) {
        ....
    }
}

我会把我的回答分成两部分,因为你提出的不是一个问题,而是两个问题。 首先说说你的这个问题:

How can we make it so that the RegistrationSqlEventHandler complete and commits BUT the RegistrationNeo4jEventHandler retries?

从命名中已经很明显两个事件处理组件(即 class you 编写包含 @EventHandler 注释方法)服务于完全不同的查询模型。第一个是 RDBMS,而第二个是通过 Neo4j 更新图形模型的目的。

因此,我发现您最终很可能会对两者有不同的非功能需求。为了能够允许对这些进行不同的配置,您必须为两者使用不同的 Event Processor 实例。事件处理器,负责管理向 您的 事件处理程序提供事件的技术方面的组件,作为配置异常处理、线程数、批处理大小等内容的地方。

请注意,事件处理器有两种类型:SubscribingEventProcessorTrackingEventProcessor。这些可以简单地描述为事件推送和事件拉取机制,后者是默认设置,因为它强制执行进一步的隔离。

要为两者配置不同的事件处理器,您可以使用 Axon 提供的配置 API。对于事件处理器,这意味着与 EventProcessingConfigurer 交互。使用它您可以定义不同的事件处理器,然后将您的事件处理组件分配给正确的实例。您可以使用的一种简便方法是在两个事件处理组件上添加 @ProcessingGroup 注释,其中包含不同的名称。 特别是如果您处于 Spring 引导环境中,就配置而言,这就足够了。

进行此隔离将确保 RegistrationNeo4jEventHandler 中的异常情况不会对 RegistrationSqlEventHandler 产生任何不良影响,反之亦然。


其次,让我们转到您的另一个问题:

Secondly, how do we stop the retrying of the event entirely upon failure?

为此,您将不得不调整事件处理过程的异常处理。 Axon在涉及到事件处理组件时,衍生出两个级别的异常处理:

  1. ListenerInvocationErrorHandler -> 负责处理@EventHandler注解方法抛出的异常。
  2. ErrorHandler -> 负责处理事件处理器中抛出的异常。

这些的默认实现将分别记录错误(使用 LoggingErrorHandler)和传播异常(使用 PropagatingErrorHandler)。

仅供参考,参考指南 this 说明了事件处理器的错误处理。

在这个问题中,您进一步指定了具有不同事件处理函数的案例。同样,如果您不想影响一个事件处理的失败导致另一个问题,您可能希望将这些问题与不同的事件处理器分开。

请注意,如果您举例说明的这四个事件处理程序只是更新查询模型,那么后续调用应该只执行相同的操作而没有任何副作用。然而,如果这些事件处理程序执行其他一些(外部的)activity,比如发送电子邮件,那绝对保证将给定的事件处理组件隔离到一个您不希望 retry/replay 的不同的事件处理器中。