RabbitMQ延时队列
1). 前提条件首先要具备已经安装**rabbitmq+erlang**,版本可以参考https://www.rabbitmq.com/which-erlang.html#compatibility-matrix
2). 在https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases中下载和自己rabbitmq相对应的版本,我的rabbitmq版本为 3.10.0 和erlang版本是23.2,rabbitmq-delayed-message-exchange的版本为rabbitmq_delayed_message_exchange-3.10.0.ez
3). 下载到了之后放到rabbitmq的plugins目录下
4). 检测rabbitmq_delayed_message_exchange是否有效,在rabbitmq的可视化界面中新建交换机![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5d7fea96817a4131bd4db90a4c7a97b4.png)
5).rabbitmq的配置 [ 重试机制是为了做滞后处理 ]
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
publisher-returns: true # 开启回退模式,然后设置rabbitTemplate.setMandatory(true);
publisher-confirm-type: correlated #开启 publisher-confirm 设置同步类型 simple:同步等待confirm结果,直到超时 correlated:异步回调,次你故意ConfirmCallback,MQ返回结果时会回调这个ComfirmCallback
template:
mandatory: true # 开启消息路由失败时的策略.turn,则调用ReturnCallback; false:直接丢弃数据
listener:
simple:
# 表示消息确认方式,其有三种配置方式,分别是none、manual和auto;默认auto
acknowledge-mode: auto
# 最小的消费者数量
concurrency: 5
# 最大的消费者数量
max-concurrency: 10
# 指定一个请求能处理多少个消息,如果有事务的话,必须大于等于transaction数量.
prefetch: 3
# 重试机制: (最大重试次数包含初次消费)
# 初次消費
# 第1次:1秒
# 第2次:1*2=2秒
# 第3次:2*2=4秒
# 第4次:4*2=8秒
# 第5次:8*2=16秒
# 第6次:16*2=32秒
# 第7次:32*2=64秒 (由于设置最大间隔时间,因此这里为50秒 )
retry:
enabled: true # 是否开启重试
max-attempts: 8 # 最大重试次数
max-interval: 50000 # 重试最大间隔时间
initial-interval: 1000 # 重试间隔(单位:毫秒)
multiplier: 2 # 间隔时间乘子,间隔时间*乘子=下一次的间隔时间,最大不能超过设置的最大间隔时间
6).rabbitmq的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
7). 之后我们就可以申明队列和交换机// 订单未支付-自动取消-延时队列
String ORDER_UN_PAY_AUTO_CLOSE_ROUTING_KEY = "order_un_pay_auto_close_key";
String ORDER_UN_PAY_AUTO_CLOSE_QUEUE = "order_un_pay_auto_close_queue";
String ORDER_UN_PAY_AUTO_CLOSE_EXCHANGE = "order_un_pay_auto_close_exchange";
----------- 订单30分钟未支付,自动取消订单 -------------
/**
* 延时队列
*/
@Bean
public Queue orderNoPayDelayQueue() {
return new Queue(ManualRabbitConstant.ORDER_UN_PAY_AUTO_CLOSE_QUEUE, true);
}
/**
* 延时交换机
*/
@Bean
public CustomExchange orderNoPayDelayExchange() {
Map<String, Object> map = new HashMap<>();
map.put("x-delayed-type", "direct");
// 交换机名称 交换机类型 是否持久化 是否自动删除 配置参数
return new CustomExchange(ManualRabbitConstant.ORDER_UN_PAY_AUTO_CLOSE_EXCHANGE,"x-delayed-message",true,false,map);
}
/**
* 延时队列和交换机绑定
*/
@Bean
public Binding orderUnPayAutoCloseBinding() {
return BindingBuilder.bind(this.orderNoPayDelayQueue())
.to(this.orderNoPayDelayExchange())
.with(ManualRabbitConstant.ORDER_UN_PAY_AUTO_CLOSE_ROUTING_KEY)
.noargs();
}
8).配置消费者信息
@Component
@RequiredArgsConstructor
public class ManualNormalConsumer implements ChannelAwareMessageListener {
private final ManualAllOrderService orderService;
/**
* 延时队列消费者 1分钟未支付则取消订单
* @param message
* @param channel
*/
@RabbitHandler
@RabbitListener(queues = { ManualRabbitConstant.ORDER_UN_PAY_AUTO_CLOSE_QUEUE })
public void onDelayMessage(Message message, Channel channel) throws IOException {
long messageDeliveryTag = message.getMessageProperties().getDeliveryTag();
System.out.println("进入延时队列中"+messageDeliveryTag);
ManualAllOrderEntity orderEntity = JSON.parseObject(message.getBody(), ManualAllOrderEntity.class);
try{
// 因为配置为自动,auto,只有有异常的时候
orderService.cancelOrder(orderEntity);
}catch (Exception e){
e.printStackTrace();
}
}
}
9).在业务中触发rabbitmq 我这边默认1分钟做测试的
private void rabbitSendMessage(ManualAllOrderEntity order){
this.rabbitTemplate.convertAndSend(ManualRabbitConstant.ORDER_UN_PAY_AUTO_CLOSE_EXCHANGE,
ManualRabbitConstant.ORDER_UN_PAY_AUTO_CLOSE_ROUTING_KEY,
JSON.toJSONString(order),
message -> {
// 配置消息延时时间
message.getMessageProperties().setHeader("x-delay", 60000);
return message;
});
}
10). 这边用支付宝沙箱做测试 下订单
没打断点,rabbitmq中没记录到