首页 > 解决方案 > 设置最大 AMQP 客户端尝试次数

问题描述

我有一个案例,我可能将 Java NPE 放入接受队列有效负载的侦听器中。我得到了多次尝试和错误:

 18:41:50.549 [processingeContainer-1] WARN  o.s.a.r.l.ConditionalRejectingErrorHandler - Execution of Rabbit message listener failed.
2019-09-24 18:41:50,551 INFO  [stdout] (processingContainer-1) org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener method 'transactionProcess' threw exception

有什么方法可以限制 AMQP 客户端尝试吗?

标签: springspring-bootamqpspring-amqp

解决方案


您确实应该修复 NPE,但您可以配置侦听器容器错误处理程序。

默认ConditionalRejectingErrorHandler将某些异常视为致命异常。

它使用DefaultExceptionStrategy具有以下代码的 a:

    private boolean isCauseFatal(Throwable cause) {
        return cause instanceof MessageConversionException // NOSONAR boolean complexity
                || cause instanceof org.springframework.messaging.converter.MessageConversionException
                || cause instanceof MethodArgumentResolutionException
                || cause instanceof NoSuchMethodException
                || cause instanceof ClassCastException
                || isUserCauseFatal(cause);
    }

    /**
     * Subclasses can override this to add custom exceptions.
     * @param cause the cause
     * @return true if the cause is fatal.
     */
    protected boolean isUserCauseFatal(Throwable cause) {
        return false;
    }

因此,使用覆盖返回 trueConditionalRejectingErrorHandler的子类配置您自己的。DefaultExceptionStrategyisUserCauseFatal()NullPointerException

然后,您将错误处理程序注入侦听器容器或侦听器容器工厂。

另一种技术是添加重试拦截器;默认情况下,仅在重试用尽后记录错误。使用 Spring Boot,默认恢复器是RejectAndDontRequeueRecoverer.

编辑

我刚刚测试了它,它工作得很好......

@SpringBootApplication
public class So58087354Application {

    public static void main(String[] args) {
        SpringApplication.run(So58087354Application.class, args);
    }

    @RabbitListener(queues = "foo")
    public void listen(String in) {
        System.out.println("here");
        throw new NullPointerException("Test");
    }

}
spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.initial-interval=1000ms
spring.rabbitmq.listener.simple.retry.max-attempts=2

here
here
2019-10-01 09:07:11.936  WARN 75435 --- [ntContainer#0-1] o.s.a.r.r.RejectAndDontRequeueRecoverer  : Retries exhausted for message (Body:'[B@6d890bbc(byte[3])' MessageProperties [headers={}, contentLength=0, receivedDeliveryMode=NON_PERSISTENT, redelivered=false, receivedExchange=, receivedRoutingKey=foo, deliveryTag=1, consumerTag=amq.ctag-mwYtmPtBplrefsOa05hG0w, consumerQueue=foo])

...

2019-10-01 09:07:11.937  WARN 75435 --- [ntContainer#0-1] s.a.r.l.ConditionalRejectingErrorHandler : Execution of Rabbit message listener failed.

...

Caused by: org.springframework.amqp.AmqpRejectAndDontRequeueException: null
    ... 19 common frames omitted


编辑2

要手动向容器工厂添加重试建议...

@Component
class ContainerRetryConfigurer {

    ContainerRetryConfigurer(AbstractRabbitListenerContainerFactory<?> factory) {
        factory.setAdviceChain(RetryInterceptorBuilder.stateless()
                .maxAttempts(2)
                .backOffOptions(1000, 1.0, 1000)
                .build());
    }

}

推荐阅读