Configuring automatic message retry using RabbitMQ and Spring Boot
In some specific situations where we are consuming messages from a queue, we may want those messages not to leave that queue if something specific has not yet happened. It got pretty abstract, right? I’ll try an example:
Imagine that a purchase was made on a website.
Now imagine that an email must be sent after the product is separated from stock.
But this email should only be sent if a condition is met and that condition is the separation of the product there in stock.
Don’t ask me if this makes sense from a business point of view, it’s just a situation to justify the retry lol.
A simple drawing would look like this:
And what would it look like in a spring boot application?
Let’s do this:
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
application.properties:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.initial-interval=5000 // the first time will wait 5 seconds to try again
spring.rabbitmq.listener.simple.retry.max-attempts=10 //will try a maximum of 10 times
spring.rabbitmq.listener.simple.retry.max-interval=300000 // the maximum interval between attempts is 5 minutes
spring.rabbitmq.listener.simple.retry.multiplier=3.0 // multiplies the range by 3
queue.name=test //queue name
Listener:
@Component
public class QueueConsumer {
@RabbitListener(queues = {"${queue.name}"})
public void receive(@Payload String fileBody) throws BusinessException {
System.out.println("Message " + fileBody + LocalDateTime.now());
if(Integer.parseInt(fileBody) == 1){
throw new BusinessException("testing for exception");
}
}
}
Main class:
@EnableRabbit
@SpringBootApplication
public class AppApplication {
public static void main(String[] args) {
SpringApplication.run(AppApplication.class, args);
}
}
Okay, that’s all we need to test this. In the first message I sent the value 2:
Then it was consumed and removed from the queue.
In the second I sent the value 1 and it will be returned to the queue because an exception happened:
Look at the intervals:
This already gives us a cool proof of concept to solve some problems.
From here, just put this according to the situations that appear in each project.