Java 在同一spring boot应用程序中多次侦听同一事件时处理axon中的异常

Java 在同一spring boot应用程序中多次侦听同一事件时处理axon中的异常,java,spring,spring-boot,cqrs,axon,Java,Spring,Spring Boot,Cqrs,Axon,我们正在将axon集成到现有的spring引导应用程序中。我们目前正在使用Axon 4.1.2和Axon服务器 例如,在注册过程中,我们启动一个RegisterCommand,该命令由RegisterAggregate读取,并启动registationdoneevent 有两个EventHandlers正在侦听此RegistrationDoneEvent。它们是RegistrationNeo4jEventHandler和RegistrationSqlEventHandler 没有例外的情况下,一

我们正在将axon集成到现有的spring引导应用程序中。我们目前正在使用Axon 4.1.2和Axon服务器

例如,在注册过程中,我们启动一个
RegisterCommand
,该命令由
RegisterAggregate
读取,并启动
registationdoneevent

有两个
EventHandlers
正在侦听此
RegistrationDoneEvent
。它们是
RegistrationNeo4jEventHandler
RegistrationSqlEventHandler

没有例外的情况下,一切正常。但是,当出现异常时,假设
Neo4JEventHandler
接收到该事件,如果出现异常,则调用
SqlEventHandler
sill,即使
SqlEventHandler
成功运行,似乎仍在
SqlEventHandler
上回滚所有内容

我们如何使
SqlEventHandler
完成并提交,而
Neo4JEventHandler
重试

第二,我们如何完全在失败后停止对事件的重试?假设我们有四个事件处理程序(HandlerA、HandlerB、HandlerC、HandlerD)侦听同一个事件。如果HandlerC失败,我们希望在修复基本问题时触发它重试,但也要确保侦听相同事件的其他处理程序不会重新运行

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

注册表集合

@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) {
        ....
    }
}
@Service
@Transactional
public class RegistrationNeo4jEventHandler { 

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

@Service
@Transactional
public class RegistrationSqlEventHandler { 

    @EventHandler
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public void on(RegistrationDoneEvent event) {
        ....
    }
}
@Service
@Transactional
public class RegistrationNeo4jEventHandler { 

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

我将把我的答案分成两部分,因为你提出的不是一个问题,而是两个问题。 首先,我们来谈谈你的这个问题:

我们如何使
RegistrationSqlEventHandler
完成并提交,而
RegistrationNeo4jEventHandler
重试

从命名来看,两个事件处理组件(即您编写的包含
@EventHandler
注释方法的类)都提供了完全不同的查询模型。第一种是RDBMS,第二种是通过Neo4j更新图形模型

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

请注意,事件处理器有两种类型:订阅事件处理器和跟踪事件处理器。这些可以很快被描述为事件推送和事件拉取机制,后者是默认机制,因为它强制进一步隔离

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

执行此分离将确保
RegistrationNeo4jEventHandler
中的异常情况不会对
RegistrationSqlEventHandler
产生任何不希望的影响,反之亦然


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

第二,我们如何完全在失败后停止对事件的重试

为此,您必须调整事件处理过程的异常处理。Axon在事件处理组件方面派生了两个级别的异常处理:

  • ListenerInvocationErrorHandler
    ->负责处理
    @EventHandler
    注释方法引发的异常
  • 负责处理事件处理器内抛出的异常的
    ErrorHandler
    ->
  • 这些操作的默认实现将分别记录错误(使用
    LoggingErrorHandler
    )和传播异常(使用
    PropagingErrorHandler

    仅供参考,参考指南必须说明事件处理器的错误处理

    在这个问题中,您将进一步使用不同的事件处理函数指定您的案例。同样,如果您不想影响一个事件处理的失败,从而导致另一个事件处理的问题,那么您可能需要将这些问题与不同的事件处理器分离


    请注意,如果您举例说明的这四个事件处理程序只是更新查询模型,那么后续调用应该只执行相同的操作,而不会产生任何副作用。但是,如果这些事件处理程序执行一些其他(外部)活动,如发送电子邮件,则肯定会保证将给定的事件处理组件分离到一个不同的事件处理器中,而您不想重试/重播该处理器。

    谢谢,这会清除很多事情,
    @ProcessingGroup
    似乎是关键。还有一个问题,我还没有开始测试,但假设在生产环境中,如果EventC失败(订阅
    GenericCommonEvent
    ),我只想在没有EventA或EventB的情况下重播EventC(即使他们听了相同的事件),那怎么可能呢?我假设通过
    @Processin进行隔离