Search code examples
javaspringspring-amqpspring-rabbitspring-retry

How to exclude specific exceptions from Spring AMQP retry policy with SimpleRetryPolicy?


I have a RabbitListener in my Spring AMQP application and I'm using a custom RabbitListenerFactory with a SimpleRetryPolicy configured for message retries. However, I want to exclude certain exceptions from being retried. Currently, my configuration looks like this:

@Bean
fun retryPolicy(): SimpleRetryPolicy {
    val exceptions = mutableMapOf<Class<out Throwable>, Boolean>(
        ValidationException::class.java to false,
        IllegalArgumentException::class.java to false,
        EntityNotFoundException::class.java to false,
    )
    return SimpleRetryPolicy(6, exceptions, true)
}

@Bean
fun retryInterceptor(customMessageRecoverer: CustomMessageRecoverer): RetryOperationsInterceptor? {
    return RetryInterceptorBuilder.stateless().retryPolicy(retryPolicy())
        .backOffOptions(1000, 2.0, 5000)
        .recoverer(customMessageRecoverer)
        .build()
}

@Bean
fun myFactory(
    configurer: SimpleRabbitListenerContainerFactoryConfigurer,
    connectionFactory: ConnectionFactory,
    customsMessageRecoverer: CustomMessageRecoverer,
): SimpleRabbitListenerContainerFactory {
    val factory = SimpleRabbitListenerContainerFactory()
    configurer.configure(factory, connectionFactory)
    factory.setAdviceChain(workMessagesRetryInterceptor(customsMessageRecoverer))
    return factory;
}

However, I've noticed that with this configuration, no retries are being executed at all, even for exceptions that are not in the exclusion list. How can I modify this configuration to both exclude specific exceptions from being retried, such as AuthoraizationException or IllegalArgumentException, and ensure that other exceptions are still retried according to the retry policy? Any code examples would be appreciated. Thanks in advance!


Solution

  • See one more constructor for that SimpleRetryPolicy:

    /**
     * Create a {@link SimpleRetryPolicy} with the specified number of retry attempts. If
     * traverseCauses is true, the exception causes will be traversed until a match or the
     * root cause is found. The default value indicates whether to retry or not for
     * exceptions (or super classes thereof) that are not found in the map.
     * @param maxAttempts the maximum number of attempts
     * @param retryableExceptions the map of exceptions that are retryable based on the
     * map value (true/false).
     * @param traverseCauses true to traverse the exception cause chain until a classified
     * exception is found or the root cause is reached.
     * @param defaultValue the default action.
     */
    public SimpleRetryPolicy(int maxAttempts, Map<Class<? extends Throwable>, Boolean> retryableExceptions,
            boolean traverseCauses, boolean defaultValue) {
    

    In your case that defaultValue is set to false with the meaning to not retry the rest not mapped exceptions. Sounds like you need exactly opposite: retry all the exception and do something specific for mapped.