0.背景
最近在我们的业务系统中遇到一个问题,
publisher
行为:convertAndSend
然后打日志。
consumer
行为:@RabbitListener
接到消息立刻打日志。
问题是,publisher
打出了发送消息的日志,consumer
没打出收到消息的日志。
基于这种情况,准备启用rabbitmq java client
的ReturnCallback
及ConfirmCallback
机制,先确认消息是否成功发到了正确的queue
里面。
之前没有用Callback
,因为对于我们的场景,Rabbitmq
还是非常稳定的,即使极少出现的异常情况,我们也有办法把丢掉的消息补发,因此没必要浪费Channel
资源去让rabbitmq server
给发送确认信息,也不想平白增加系统复杂性。
1.代码实现
一般我们使用rabbitmq
可能会配置下面几个bean
(不论通过何种方式,xml
,@Configuretion
,或者spring boot
的autoconfigure
),在此基础上,添加一些属性设置:
@Configuration
public class MqConfig {
@Value("${rabbitmq.enableConfirm}")
private boolean enableConfirm;
@Value("${rabbitmq.enableReturn}")
private boolean enableReturn;
@Value("${rabbitmq.enableMessageCorrelation}")
private boolean enableMessageCorrelation;
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
//省略其它属性设置...
//根据配置决定是否开启 Confirm 机制
connectionFactory.setPublisherConfirms(enableConfirm);
//根据配置决定是否开启 Return 机制
connectionFactory.setPublisherReturns(enableReturn);
return connectionFactory;
}
@Bean
public RabbitTemplate rabbitTemplate() throws Exception {
//根据配置决定使用哪种 RabbitTemplate
RabbitTemplate template = enableMessageCorrelation ?
new CorrelationRabbitTemplate(connectionFactory()) :
new RabbitTemplate(connectionFactory());
//省略其它属性设置...
//如果启用 Confirm 机制,设置 ConfirmCallback
if (enableConfirm) {
template.setConfirmCallback(confirmCallback());
}
//如果启用 Return 机制,设置 ReturnCallback,及打开 Mandatory
if (enableReturn) {
template.setReturnCallback(returnCallback());
template.setMandatory(true);
}
return template;
}
}
对于Publisher
而言,以上两个bean
足以。
下面是 RabbitTemplate
中需要的ConfirmCallback
和ReturnCallback
:
@Bean
@ConditionalOnMissingBean(value = RabbitTemplate.ConfirmCallback.class)
public RabbitTemplate.ConfirmCallback confirmCallback() {
return new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
// do something ...