SpringBoot integrates RabbitMQ
1. Auto mode (automatic ACK)
RabbitMQ is in auto mode by default. When the monitoring consumer method is executed normally, Spring will automatically return ack to RabbitMQ for confirmation; if an exception occurs, it will return nack to RabbitMQ for consumption failure.
application.yml configures RabbitMQ consumer ACK response mode
spring:
rabbitmq:
listener:
simple:
# none(无应答模式) auto(自动应答模式) manual(手动应答模式)
acknowledge-mode: auto
Two, none mode (no ACK)
RabbitMQ believes that all messages will be successfully consumed, so RabbitMQ will delete the message immediately after delivering the message
application.yml configures RabbitMQ consumer ACK response mode
spring:
rabbitmq:
listener:
simple:
# none(无应答模式) auto(自动应答模式) manual(手动应答模式)
acknowledge-mode: none
3. Manual mode (manual ACK)
After processing the business, the developer calls the API encapsulated by RabbitMQ, and returns an ack to RabbitMQ to confirm the success or failure of the consumption
application.yml configures RabbitMQ consumer ACK response mode
spring:
rabbitmq:
listener:
simple:
# none(无应答模式) auto(自动应答模式) manual(手动应答模式)
acknowledge-mode: manual
4. Consumers fail to retry
You can use Spring's own automatic retry mechanism. When an exception occurs in the consumer, retry locally within the consumer; instead of letting the message return to the queue immediately and then let RabbitMQ re-deliver, it will cause the CPU to soar. (This will lead to an infinite loop -> once the message is abnormal, it will be continuously put back into the queue and resent to the consumer).
application.yml configuration
Define queues and exchanges
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RetryQueueConfig {
//定义direct类型交换机
@Bean
public DirectExchange retryExchange() {
return ExchangeBuilder.directExchange("retry.exchange").build();
}
//定义持久化队列
@Bean
public Queue retryQueue() {
return new Queue("retry.queue",true,false,false);
}
@Bean
public Binding retryQueueBinding(Queue retryQueue, DirectExchange retryExchange) {
return BindingBuilder.bind(retryQueue).to(retryExchange).with("retry");
}
}
mock producer
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class RetryQueueTest {
@Autowired
private RabbitTemplate rabbitTemplate;
//模拟生产者
@Test
public void test(){
rabbitTemplate.convertAndSend("retry.exchange","retry","模拟消息异常");
}
}
Console output
The message is deleted after three retries
Recovery strategy after failed retries
In the local retry just now, after reaching the maximum number, the message will be discarded, which is determined by Spring's internal mechanism.
However, in fact, after retrying multiple consumptions and still failing, SpringAMQP provides the MessageRecoverer interface, which defines different recovery strategies that can be used to further process messages:
RejectAndDontRequeueRecoverer: After the retries are exhausted, reject directly and lose the message. is the default processing strategy
ImmediateRequeueMessageRecoverer: After retries are exhausted, nack is returned, and the message is re-queued
RepublishMessageRecoverer: After the retries are exhausted, deliver the failure message to the specified exchange
In actual development, a more elegant solution is RepublishMessageRecoverer, which reposts failure messages to a queue dedicated to storing exception messages, waiting for subsequent manual processing.
RepublishMessageRecoverer policy code
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RepublishMessageRecovererConfig {
/*
* 消息消费失败后的恢复策略:使用RepublishMessageRecoverer策略:重试次数耗尽后,将失败消息投递到指定的交换机
*/
@Bean
public MessageRecoverer republishMsgRecoverer(RabbitTemplate rabbitTemplate) {
return new RepublishMessageRecoverer(rabbitTemplate, "error.exchange", "error");
}
//定义Topic类型交换机
@Bean
public TopicExchange errorExchange() {
return ExchangeBuilder.topicExchange("error.exchange").build();
}
//定义队列
@Bean
public Queue errorQueue() {
return QueueBuilder.durable("error.queue").build();
}
//队列和交换机绑定
@Bean
public Binding errorQueueBinding(TopicExchange errorExchange, Queue errorQueue) {
return BindingBuilder.bind(errorQueue).to(errorExchange).with("error.#");
}
}
In this way, after the exception message retries are exhausted, it will be delivered to the specified exception queue and wait for manual processing.