kleenxcoder
kleenxcoder

Reputation: 480

Spring AMQP @RabbitListener custom retry on business error best practice

Following scenario: I have a @RabbitListener picking up messages from RabbitMQ. Sometimes the message runs into an error because I can not find the related business object. In this case I have no possibility to reply to the sender so I just want to ignore this message after certain amount of retry.

My solution: In my @RabbitListener whenever it is not possible to find the business object I throw a custom runtime exception. In my configuration I have a RetryOperationsInterceptor with max attempts and a custom recoverer.

What is the best practice for handling such cases? Can I configure diffrent recoverer class when having more than one @RabbitListener?

See my configuraion:

@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setMessageConverter(new CustomMessageConverter());
    factory.setConnectionFactory(connectionFactory());
    factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
    factory.setConcurrentConsumers(1);
    factory.setMaxConcurrentConsumers(20);

    Advice[] adviceChain = new Advice[] { interceptor() };
    factory.setAdviceChain(adviceChain);
    return factory;
}

@Bean
RetryOperationsInterceptor interceptor() {
    return RetryInterceptorBuilder.stateless()
            .maxAttempts(5)
            .recoverer(new CustomRejectAndRecoverer())
            .build();
}

And this is my CustomRejectAndRecoverer:

public class CustomRejectAndRecoverer implements MessageRecoverer {

    @Override
    public void recover(Message message, Throwable cause) {
        if (ExceptionUtils.getRootCause(cause) instanceof BusinessObjectNotFoundRuntimeException) {
            throw new ListenerExecutionFailedException("Retry Policy Exhausted",
                    new AmqpRejectAndDontRequeueException(cause), message);
        }
    }
}

Upvotes: 1

Views: 3333

Answers (2)

Gary Russell
Gary Russell

Reputation: 174769

You currently need a different container factory for each different retry configuration.

In 2.0, we have added a new errorHandler attribute to the annotation so each listener can have a customized error handler, regardless of the container factory it was created by.

This was in the first milestone release; the current milestone is M2 and M3 will be out shortly. The GA release is expected in June.

Upvotes: 3

Artem Bilan
Artem Bilan

Reputation: 121550

If common logic from the shared SimpleRabbitListenerContainerFactory doesn't fit your requirements for particular @RabbitListener, you have to declare a new one, with those custom options, e.g. a new MessageRecoverer on the matter.

For that purpose the @RabbitListener has attribute:

/**
 * The bean name of the {@link org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory}
 * to use to create the message listener container responsible to serve this endpoint.
 * <p>If not specified, the default container factory is used, if any.
 * @return the {@link org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory}
 * bean name.
 */
String containerFactory() default "";

Upvotes: 0

Related Questions