0

I have the following two cases

  1. In case of ExceptionA : retrying for finite number of times and finally when number of retrials exhausted, message is written in a dead letter queue
  2. In case of ExceptionB : simply, message should be written to dead letter queue

I want to support the two cases on the same listener container factory and the same queue.

I already have the following configuration to support case 1 successfully:

@Bean
public RetryOperationsInterceptor workMessagesRetryInterceptor() {
        return RetryInterceptorBuilder.stateless()
                .maxAttempts(5)
                .backOffOptions(1000, 2, 10000)
                .recoverer(new RejectAndDontRequeueRecoverer())
                .build();
    }




@Bean
public SimpleRabbitListenerContainerFactory myRabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
  SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
  factory.setConnectionFactory(connectionFactory);
  factory.setMaxConcurrentConsumers(8);
  factory.setAdviceChain(workMessagesRetryInterceptor());


  return factory;
}`

Now I want to extend the previous configuration to support case 2 too.


Edit, thanks Gary for your fast response.

Here you are my new configuration, but I still get retrials on both the two exceptions : ListenerExecutionFailedException , AmqpRejectAndDontRequeueException

@Bean
    public SimpleRetryPolicy rejectionRetryPolicy(){

        Map<Class<? extends Throwable> , Boolean> exceptionsMap = new HashMap<Class<? extends Throwable> , Boolean>();
        exceptionsMap.put(ListenerExecutionFailedException.class, true); //retriable
        exceptionsMap.put(AmqpRejectAndDontRequeueException.class, false);//not retriable


        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(5 , exceptionsMap );




        return retryPolicy;
    }

    @Bean
    public RetryOperationsInterceptor workMessagesRetryInterceptor() {
        return RetryInterceptorBuilder.stateless().retryPolicy(rejectionRetryPolicy())

                //.backOffOptions(1000, 2, 10000)
                //.recoverer(new RejectAndDontRequeueRecoverer())
                .build();
    }
halfer
  • 19,824
  • 17
  • 99
  • 186
Shady Ragab
  • 705
  • 10
  • 26

1 Answers1

4

Provide a SimpleRetryPolicy with a map of exceptions and booleans (whether or not to retry). You can optionally traverse the exception cause tree to find the specific exception. See the Javadocs for SimpleRetryPolicy.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • You need to set the `traverseCauses` boolean to `true` because that exception gets wrapped in a `ListenerExecutionFailedException`. This is explained [in the documentation](http://docs.spring.io/spring-amqp//reference/html/_reference.html#_exception_classification_for_retry). – Gary Russell Sep 01 '16 at 15:26
  • yes, that's it...But the message is not routed to the dead letter queue in both the two cases even with uncommenting the line : `recoverer(new RejectAndDontRequeueRecoverer())` – Shady Ragab Sep 01 '16 at 16:11
  • Oh, I didn't notice your exceptions - you can't use those two because the `AmqpRejectAndDontRequeueException` is wrapped in the `ListenerExecutionFailedException` and we'll find that one first. You will have to throw a different exception and coerce it to an `AmqpRejectAndDontRequeueException` in a custom error handler. See [documentation about `FatalExceptionStrategy`](http://docs.spring.io/spring-amqp//reference/html/_reference.html#exception-handling). However, changing the policy won't affect DLX/DLQ routing if a message is rejected it will be routed to the DLX/DLQ by rabbit. – Gary Russell Sep 01 '16 at 16:29
  • i.e. You can't use `AmqpRejectAndDontRequeueException` to signal you don't want retry. If you want to retry for all exceptions except one, you need to throw `MyException` and configure the `FatalExceptionStrategy` to return true for that exception so the error handler will throw an `AmqpRejectAndDontRequeueException`. – Gary Russell Sep 01 '16 at 16:33