当 Axon 抛出异常时 Spring 返回 HTTP 状态 200

问题描述 投票:0回答:1

我从 Spring 中通过 HTTP 请求调用的命令处理程序抛出一个

org.springframework.web.server.ResponseStatusException
。通常我希望响应携带由异常定义的 HTTP 状态。

但是,Spring 返回状态 200,而 Axon 记录:

Command 'com.my.Command' resulted in com.my.CustomResponseStatusException

我在命令网关上调用

send
还是
sendAndWait
都没有区别。控制器直接返回结果
CompletableFuture

是否有我缺少的配置?

我抛出的异常是一个扩展的

ResponseStatusException
,它允许我提供自定义域错误代码与 HTTP 状态错误代码:

public abstract class DomainException extends ResponseStatusException {

    public final String errorCode;

    public DomainException(HttpStatus status, String errorCode, String message) {
        super(status, message);
        this.errorCode = errorCode;
    }

    public DomainException(HttpStatus status, String errorCode, String message, Throwable cause) {
        super(status, message, cause);
        this.errorCode = errorCode;
    }
}

这些具体实现之一是:

public class MembershipAlreadyExistsException extends DomainException {

    public MembershipAlreadyExistsException(Id<Member> memberId, Id<Club> clubId) {
        super(HttpStatus.BAD_REQUEST, DomainError.MEMBERSHIP_ALREADY_EXISTS.name(), "There is already a membership of member with ID " + memberId + " and club with ID " + clubId);
    }
}

即使我提供自定义

@ControllerAdvice
也没有调用任何异常处理程序方法,因为异常似乎是在命令网关中捕获并记录的。

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class DefaultExceptionHandler extends ResponseEntityExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(DefaultExceptionHandler.class);

    @ExceptionHandler(UndeclaredThrowableException.class)
    protected ResponseEntity<?> handleUndeclaredException(UndeclaredThrowableException exception) {
        logger.error("Undeclared Exception", exception);
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(DomainException.class)
    protected ResponseEntity<?> handleDomainException(DomainException exception) {
        logger.error("Domain Exception", exception);
        return new ResponseEntity<>(exception.errorCode, exception.getStatusCode());
    }

    @ExceptionHandler(JSR303ViolationException.class)
    protected ResponseEntity<?> handleJSR303ViolationException(JSR303ViolationException exception) {
        logger.debug("Request was violating one ore more constraints", exception);
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }
}

有趣的是,如果我这样做:

@RequestMapping("/invite")
    public CompletableFuture<Void> enrollMember(@RequestBody InviteMemberByEmail inviteMemberByEmail) {
        try {
            logger.trace("Before sending command");
            CompletableFuture<Void> result = commandGateway.sendAndWait(inviteMemberByEmail);
            logger.trace("After sending command");
            return result;

        } catch (Exception e) {
            logger.trace("Exception caught", e);
            throw e;
        }
    }

输出为:

2024-03-23T09:22:29.073+01:00 TRACE 20808 --- [nio-8081-exec-2] a.z.c.i.http.MemberController            : Before sending command
2024-03-23T09:22:29.930+01:00  WARN 20808 --- [nio-8081-exec-2] o.s.c.annotation.AnnotationTypeMapping   : Support for convention-based annotation attribute overrides is deprecated and will be removed in Spring Framework 6.2. Please annotate the following attributes in @org.axonframework.modelling.command.AggregateIdentifier with appropriate @AliasFor declarations: [routingKey]
2024-03-23T09:22:29.949+01:00  WARN 20808 --- [nio-8081-exec-2] o.a.c.gateway.DefaultCommandGateway      : Command '--redacted--.api.InviteMemberToClub' resulted in --redacted--.domain.exceptions.MembershipAlreadyExistsException(400 BAD_REQUEST "There is already a membership of member with ID f6628294-4021-70d1-89cd-0ee5e7e99c8f and club with ID 780f0cc1-8eaf-4968-bcbd-8f92fb678260")
2024-03-23T09:22:29.950+01:00 TRACE 20808 --- [nio-8081-exec-2] a.z.c.i.http.MemberController            : After sending command

我已经确认它实际上是

SimpleCommandBus
的一个实例,但注意到某种形式的
FailureLoggingCallback
:

spring-boot axon
1个回答
0
投票

我一直在检查

SimpleCommandBus
DefaultCommandGateway
的实现,但是
DefaultCommandGateway
不会重新抛出异常的唯一情况是 CommandResultMessage 不异常。
请注意,

CommandResultMessage

是Axon框架创建的用于携带命令处理结果的对象。因此,如果抛出异常,它将被捕获在

CommandResultMessage
中。这样做后,它的状态将被设置为异常。
因此,此时我只能得出结论,命令处理程序可能正在执行有关异常抛出的操作。或者,聚合正在其他地方捕获异常。但是,为了能够推断出这一点,我需要要求您:

使用命令处理程序和
    Any
  1. 拦截器更新您的问题,或者, 提供一个示例项目,以便我能够在本地重现困境。这将使我能够调试相关场景。
即使我在命令处理程序中抛出异常,从跟踪更改为订阅事件处理器也可以解决问题(?)

TrackingEventProcessor

切换为

SubscribingEventProcessor
将导致使用相同的线程来处理事件。因此,解决此问题的唯一方法是事件处理程序抛出一个异常,该异常确实会导致
CommandResultMessage
变得异常。
    

© www.soinside.com 2019 - 2024. All rights reserved.