标题:将异常从 Axon Saga 传播到 Spring Boot REST 控制器

Title: Propagating Exceptions from Axon Saga to Spring Boot REST Controller

提问人:Hadi Rifaii 提问时间:10/19/2023 更新时间:10/19/2023 访问量:46

问:

我正在做一个利用 Axon 框架和 Spring Boot 来实现 CQRS 和事件溯源模式的项目。在这个项目中,我定义了一个 Saga 来处理特定的业务流程。在此 Saga 中,当不满足某些条件时,我会抛出自定义 InvalidOrderException。这是我的传奇的简化版本:

@Slf4j
@NoArgsConstructor
public class OrderSaga {
    // ...
    @StartSaga
    @SagaEventHandler(associationProperty = "orderId")
    @EventHandler
    public void handle(OrderCreatedEvent orderCreatedEvent) {
        // ...
        try {
            commandGateway.sendAndWait(reserveProductCommand);
        } catch (CommandExecutionException ex) {
            rollbackReservations();
            throw new InvalidOrderException("The product ID: " + productId + " provided in the order is invalid ");
        }
        // ...
    }
    // ...
}

我想在我的 REST 控制器中处理此 InvalidOrderException,从该控制器发送启动此 Saga 的命令,以通知用户出现问题。这是我的 REST 控制器的相关部分:

public class OrderController {
    // ...
    @PostMapping
    public ResponseEntity<ReadOrderDto> createOrder(@RequestBody CreateOrderDto createOrderDto){
        CreateOrderCommand createOrderCommand = new CreateOrderCommand(
            // ...
        );

        commandGateway.sendAndWait(createOrderCommand);

        return new ResponseEntity<>(
            createOrderCommand.toToReadProductDto(), HttpStatus.OK
        );
    }
    // ...
}

为了处理 InvalidOrderException,我尝试创建一个用 @RestControllerAdvice 注释的 GlobalExceptionHandler 类,如下所示:

public class GlobalExceptionHandler {
    @ExceptionHandler(InvalidOrderException.class)
    public ResponseEntity<String> handleProductServiceException(InvalidOrderException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
}

但是,此 GlobalExceptionHandler 不会捕获从 Saga 引发的异常。我正在寻找一种方法将此异常传播回 REST 控制器,以向客户端发送有意义的错误响应。

我还使用了 Axon 的@ExceptionHandler注解,但这仅在在同一类中抛出异常时才有效,所以这没有帮助。

是否有推荐的方法来处理Spring Boot REST控制器中Axon Saga抛出的此类异常,特别是捕获和响应最初发送命令的这些异常?

谢谢。

spring-boot rest 异常 轴突 传奇

评论


答:

2赞 Gerard Klijs 10/19/2023 #1

我不确定将某些东西从 Saga 返回给其余控制器是否是正确的方法。由于 Saga 用于可能很长的异步运行进程,因此从最初的 rest 调用开始,我只期望失败或 Ok,订单开始返回。

在Saga中,您可以发送相应的命令或事件,以便可以创建可以从中检索状态的投影。因此,例如,您可以对订单启动订阅查询,以在 UI 中提供反馈。

评论

0赞 Hadi Rifaii 10/19/2023
感谢您的回复,由于我是从控制器在发布路由中发送命令,因此如何对订单启动订阅查询并在发布发布路由中使用其信息?我有点困惑,我怎么能做到这一点,但我尝试了一点不同的方法,即从传奇中发布一个事件,并在订单服务中的其他地方处理它,在那里抛出异常并从控制器处理它,但该事件没有得到处理。
0赞 Gerard Klijs 10/19/2023
不在 post 路由中,它可以是命令正常时来自客户端的调用。对于订阅,可以使用 websocket 或服务器发送的事件。可能的问题是您创建的事件不是域事件,而这不应该是域事件。事件应由事件处理器处理,该处理器是投影的一部分,可以查询。这并不意味着直接转到控制器。
0赞 Gerard Klijs 10/19/2023
也许一个例子效果更好。在这种情况下,将发送命令,并立即启动订阅查询。然后映射要返回的成功响应。但您也可以分两个步骤完成。
0赞 Hadi Rifaii 10/21/2023
谢谢你的回答,它使用订阅查询来解决它,有没有类似的方法来处理查询,比如说当客户端想要获取一个不存在的订单时?
0赞 Gerard Klijs 10/22/2023
如果订单不存在,可以直接从查询中返回错误吗?