一、需求
- 订单未支付超过一定时间自动取消、会话请求创建一定时间无响应自动取消
- 定时任务也可实现,但有两点问题:a) 扫描过于频繁,对性能影响大 b) 扫描不及时
二、解决
- 使用Rabbitmq延迟队列
- 使用社区提供的延迟队列插件实现
三、步骤
- 简介
- https://github.com/rabbitmq/rabbitmq-delayed-message-exchange
- 下载
- https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases
- 使用
- 下载文件rabbitmq_delayed_message_exchange.ez拷贝到程序目录/rabbitmq/lib/rabbitmq_server/plugins
- 启用插件:rabbitmq-plugins enable rabbitmq_delayed_message_exchange
四、Java使用
1、定义延迟队列和Exchange绑定关系(示例类型为direct,也可以用其它类型,如fanout)
@Configuration
public class MqDelayConfig {
@Bean
public Queue delayQueue() {
return new Queue("delayQueue");
}
@Bean
CustomExchange delayCustomExchange() {
Map<String, Object> args = new HashMap<>(1);
args.put("x-delayed-type", "direct");
return new CustomExchange("delayCustomExchange", "x-delayed-message", true, false, args);
}
@Bean
Binding binding() {
return BindingBuilder.
bind(delayQueue()).
to(delayCustomExchange()).
with("delayQueue").
noargs();
}
}
2、发送消息
rabbitTemplate.convertAndSend("delayCustomExchange", "delayQueue", msg, message -> {
// 发布延迟消息 持久化消息
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
// 设置延迟时间 毫秒
message.getMessageProperties().setDelay(10 * 1000);
return message;
}, correlationData);
3、消息消费
@RabbitListener(queues = "delayQueue")
public void delayQueue() {
// 消费逻辑
// Ack
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
五、其它
1、Rabbitmq Management 什么时候可以看到延迟队列消息?
- 消息发送成功不会看到,只有延迟时间到了投递到队列中才能看到
2、过期消息会自动清除吗?
- 过期消息不会自动清除,一直在队列中保留。 消费者启动后会消费
3、不同过期时间的消息怎样消费?
- 比如先写入一条2分钟过期的消息,再写入一条1分钟过期的消息,消费者会先消费1分钟过期的消息,也就是后写入队列的消息