RabbitMQ 延时消息队列
一、前言
在做商城项目的过程中,遇到了这样一个问题:
订单要在30分钟内未支付的情况下系统自动关闭此订单。当时考虑了三种方案:
①写一个定时任务去轮询
②在触发点开线程进行调度
③使用rabbitmq建立延时队列
使用第一种如果对时间要求过高,对数据库压力比较大,使用第二种如果在线程开启后,用户付完款,该订单的线程又不能主动释放。白白占用线程,而刚好我们这个项目有使用rabbitmq做消息队列,于是最后使用mq在做延时队列。
二、实现
对于第一种实现方案比较简单: 使用
1 //秒 分 时 日 月 年/星期 2 @Scheduled(cron = "0/1 * * * * ?") 3 public void task() { 4 ...... 5 }
对于第二种方案:
RabbitMQ:
RabbitMQConfiguration查看之前的:RabbitMQ 消息发送、消息监听
1 @Service 2 public class AmqpTask { 3 4 private static Logger logger = LoggerFactory.getLogger(AmqpTask.class); 5 //30分钟 6 private static final Integer time = 1000 * 60 * 1 * 30; 7 //设置 DLX 8 private static final String x_dead_letter_exchange = "amq.direct"; 9 //设置 routing key 用于 DLX 分发消息 10 private static final String x_dead_letter_routing_key = "message_ttl_routingKey"; 11 12 @Autowired 13 private RabbitMQConfiguration rabbitMQConfiguration; 14 15 /** 16 * @param message 发送的延时消息 17 * @throws IOException 18 */ 19 public void task(String message) { 20 ConnectionFactory factory = new ConnectionFactory(); 21 factory.setHost(rabbitMQConfiguration.getHost()); 22 factory.setUsername(rabbitMQConfiguration.getUserName()); 23 factory.setPassword(rabbitMQConfiguration.getPassword()); 24 Connection connection = null; 25 Channel channel = null; 26 try { 27 connection = factory.newConnection(); 28 channel = connection.createChannel(); 29 HashMap<String, Object> arguments = new HashMap<>(); 30 arguments.put("x-dead-letter-exchange", x_dead_letter_exchange); 31 arguments.put("x-dead-letter-routing-key", x_dead_letter_routing_key); 32 channel.queueDeclare(rabbitMQConfiguration.getOrderClosePublishQueueName(), true, false, false, arguments); 33 // 声明队列 34 channel.queueDeclare(rabbitMQConfiguration.getOrderCloseQueueName(), true, false, false, null); 35 // 绑定路由 36 channel.queueBind(rabbitMQConfiguration.getOrderCloseQueueName(), x_dead_letter_exchange, x_dead_letter_routing_key); 37 // 设置延时属性 38 AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder(); 39 // 持久性 non-persistent (1) or persistent (2) 40 AMQP.BasicProperties properties = builder.expiration(String.valueOf(time)).deliveryMode(2).build(); 41 // routingKey =delay_queue 进行转发 42 channel.basicPublish("", rabbitMQConfiguration.getOrderClosePublishQueueName(), properties, message.getBytes()); 43 System.out.println("sent message: " + message + ",date:" + System.currentTimeMillis()); 44 // 关闭频道和连接 45 channel.close(); 46 connection.close(); 47 } catch (IOException e) { 48 e.printStackTrace(); 49 logger.error("IOException e:" + e.getMessage()); 50 } catch (TimeoutException e) { 51 e.printStackTrace(); 52 logger.error("TimeoutException e:" + e.getMessage()); 53 } 54 55 }