利用死信机制来实现重试和时间间隔机制,可以控制单独的队列重试次数和时间。
总体的思路就是,将消费失败的消息发送到一个有过期时间的队列中,该队列没有消费者,并且配置有死信队列,那到了超时时间后,RabbitMQ会自动将该消息推送至死信队列,监听死信队列的消费者,获取消息后消费,从而实现控制时间间隔发送。而重试次数,可以通过在消息头中设置增加一个参数来实现。
下面是我的实现方法:
首先需要声明一个交换机和四个队列,将四个队列都绑定到交换机上。
String E_NOTIFY_CALLBACK = "E.NOTIFY_CALLBACK"; // 交换机
String Q_NOTIFY_CALLBACK_NORMAL = "Q.NOTIFY_CALLBACK@NORMAL"; // 正常队列
String Q_NOTIFY_CALLBACK_READY = "Q.NOTIFY_CALLBACK@REDAY"; // 预备队列(预备重试)
String Q_NOTIFY_CALLBACK_RETRY = "Q.NOTIFY_CALLBACK@RETRY"; // 重试队列
String Q_NOTIFY_CALLBACK_DEAD = "Q.NOTIFY_CALLBACK@DEAD"; // 死信队列
其中READY的队列,比较特殊,也就是RETRY的死信队列,需要设置消息的超时时间。
队列和交换机可以声明在RabbitConfig中,或者直接在监听的方法上用注解形式声明。
// 声明交换机
@Bean
public DirectExchange notifyCallbackExchange() {
return new DirectExchange(MQConfig.E_NOTIFY_CALLBACK);
}
// 声明预备队列
@Bean
public Queue notifyCallbackReadyQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", 10000); // 队列消息超时时间
args.put("x-dead-letter-exchange", MQConfig.E_NOTIFY_CALLBACK); // 死信交换机
args.put("x-dead-letter-routing-key", "retry"); // 死信路由
return new Queue(MQConfig.Q_NOTIFY_CALLBACK_READY, true, false, false, args);
}
// 绑定预备队列到交换机,路由Key为ready
@Bean
public Binding bindNotifyCallbackReadyQueue() {
return BindingBuilder.bind(notifyCallbackReadyQueue()).to(notifyCallbackExchange())