RabbitMq DLX 实现延迟队列

我们可以把死信队列就当成延迟队列。

具体来说是这样:

假如一条消息需要延迟 30 分钟执行,我们就设置这条消息的有效期为 30 分钟,同时为这条消息配置死信交换机和死信 routing_key,并且不为这个消息队列设置消费者,那么 30 分钟后,这条消息由于没有被消费者消费而进入死信队列,此时我们有一个消费者就在“蹲点”这个死信队列,消息一进入死信队列,就立马被消费了。

 

配置:mqConfig 

package com.pay.fyServe.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

import java.util.HashMap;
import java.util.Map;

import static com.pay.fyServe.constants.FyConstant.*;


@SpringBootConfiguration
public class FyServeMqConfig {


    //region
    /**
     * 声明正常队列
     *
     * @return
     */
    @Bean
    public Queue fyServeRefreshQueue() {
        //只需要在声明业务队列时添加x-dead-letter-exchange,值为死信交换机
        Map<String, Object> map = new HashMap<>(1);
        map.put("x-dead-letter-exchange", FY_SERVE_REFRESH_DLK_EXCHANGE);
        //该参数x-dead-letter-routing-key可以修改该死信的路由key,不设置则使用原消息的路由key
        map.put("x-dead-letter-routing-key", FY_SERVE_REFRESH_DLK_ROUTE_KEY);
        return new Queue(FY_SERVE_REFRESH_QUEUE, true, false, false, map);
    }

    //声明交换机
    @Bean
    public DirectExchange fyServeRefreshExchange() {
        return new DirectExchange(FY_SERVE_REFRESH_EXCHANGE, true, false);
    }


    //声明死信交换机
    @Bean
    public DirectExchange fyServeRefreshDlkExchange() {
        return new DirectExchange(FY_SERVE_REFRESH_DLK_EXCHANGE, true, false);
    }

    //声明死信队列
    @Bean
    public Queue fyServeRefreshDlkQueue() {
        return new Queue(FY_SERVE_REFRESH_DLK_QUEUE, true, false, false);
    }

    //正常交换机-->正常队列
    @Bean
    public Binding fyServeRefreshBind() {
        return BindingBuilder.bind(this.fyServeRefreshQueue()).to(fyServeRefreshExchange()).with(FY_SERVE_REFRESH_ROUTE_KEY);
    }

    //死信交换机-->死信队列
    // (正常队列 超时后 ——> 死信交换机->死信队列 )-->
    // 因此,向正常交换机发消息,监听死信队列,就可以实现消息延时消费
    @Bean
    public Binding fyServeRefreshDlkBind() {
        return BindingBuilder.bind(fyServeRefreshDlkQueue()).to(fyServeRefreshDlkExchange()).with(FY_SERVE_REFRESH_DLK_ROUTE_KEY);
    }
    //endregion

}

 

封装方法:RabbitUtil

public class RabbitUtil {

    @Autowired
    private RabbitTemplate rabbitTemplate;


    public <T> void send(String exchange, String routeKey, T data, int delay) {
        rabbitTemplate.convertAndSend(exchange, routeKey, data, message -> {
            //设置消息的过期时间,是以毫秒为单位的
            message.getMessageProperties().setExpiration(String.valueOf(delay * 1000));
            return message;
        });
    }


    public <T> void send(String topic, T data) {
        rabbitTemplate.convertAndSend(topic, data);
    }


}

 

 

调用:

    @Autowired
    private RabbitUtil rabbitUtil;

    rabbitUtil.send(FyConstant.FY_SERVE_REFRESH_EXCHANGE, FyConstant.FY_SERVE_REFRESH_ROUTE_KEY, orderInfo.getId(), 5);

 

异步监听:

@Slf4j
@Component
public class FyServeRefreshListener {




    @RabbitHandler
    @RabbitListener(queues = FyConstant.FY_SERVE_REFRESH_DLK_QUEUE, containerFactory = "containerFactory") // 队列指向死信队列
    public void process(Long orderId) {
        log.info("开始查询订单");
     .......其他数据处理
    }
}

 

参考文章:RabbitMQ 实现延迟队列的两种方式__江南一点雨的博客-CSDN博客

posted @ 2023-10-10 10:00  fnasklf  阅读(42)  评论(0编辑  收藏  举报