java - 在同一个 Spring Boot 应用程序中多次监听同一事件时处理轴突中的异常

标签 java spring spring-boot cqrs axon

我们正在将 axon 集成到我们现有的 Spring Boot 应用程序中。我们目前使用的是 Axon 4.1.2 和 Axon Server。

例如,在注册过程中,我们触发 RegisterCommand ,由 RegisterAggregate 读取并触发 RegistrationDoneEvent .

有两个EventHandlers听这个RegistrationDoneEvent 。分别是RegistrationNeo4jEventHandlerRegistrationSqlEventHandler .

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

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

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

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

注册聚合

@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) {
        ....
    }
}

注册Neo4jEventHandler

@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?

从命名中可以明显看出,两个事件处理组件(即您编写的包含 @EventHandler 注解方法的类)都提供完全不同的查询模型。第一个目标是 RDBMS,而第二个目标是通过 Neo4j 更新图形模型。

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

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

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

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


其次,让我们讨论您的另一个问题:

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

为此,您必须调整事件处理过程的异常处理。当涉及到事件处理组件时,Axon 派生出两个级别的异常处理:

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

它们的默认实现将分别记录错误(使用LoggingErrorHandler)并传播异常(使用PropagatingErrorHandler)。

仅供引用,引用指南有 this说说事件处理器的错误处理。

在这个问题中,您将使用不同的事件处理函数进一步指定您的情况。同样,如果您不想影响一个事件处理的失败而导致另一个事件处理出现问题,您可能希望将这些问题与不同的事件处理器隔离。

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

关于java - 在同一个 Spring Boot 应用程序中多次监听同一事件时处理轴突中的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61361916/

相关文章:

java - 需要正则表达式来格式化 php 中的文件

java - 无法从 java 客户端调用 HTTPS 不受信任的 URL

Spring Boot - 加载初始数据

spring-boot - 服务器故障后 Spring 批处理文件恢复

用于网络摄像头访问的 Java 与 Flash

java - 为什么只有我添加到 JFrame 的最后一个 JPanel 才会调整大小?

java - namedParameterJdbctemplate 更新,包含多个要更新的字段

java - Spring 启动服务器接收带有 %20 而不是空间的参数

java - 为什么我的自定义 DataSource getConnection() 抛出 "SQLException: The url cannot be null"?

java - Spring Boot 反序列化蛇形案例到 Camel 案例失败。无法将 "some_value"反序列化为 "someValue"