RabbitMQ延迟队列及实战

延迟队列

延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费

延迟队列多用于需要延迟工作的场景。
如安全工单超过 24 小时未处理,则自动拉企业群提醒相关责任人。
用户下单外卖以后,距离超时时间还有 10 分钟时提醒外卖小哥即将超时。
延迟消费:
用户生成订单之后,需要过一段时间校验订单的支付状态,如果订单仍未支付则需要及时地关闭订单。
用户注册成功之后,需要过一段时间比如一周后校验用户的使用情况,如果发现用户活跃度较低,则发送邮件或者短信来提醒用户使用。
延迟重试:
比如消费者从队列里消费消息时失败了,但是想要延迟一段时间后自动重试。

项目结构

在这里插入图片描述
如图:
p:生产者
C:消费者
X,Y为直连交换机,其中Y为死信交换机
A-D为队列,其中A,B为固定时间的延迟队列,C为指定时长的延迟队列,D为死信队列

SpringBoot中整合RabbitMq

添加依赖

 	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

配置文件

spring:
  application:
    name: rabbitmq-provider
  rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: admin

配置类代码

下面新建配置类,声明队列,交换机,并进行绑定

/**
 * 延迟队列+死信队列配置类
 */
@Configuration
public class TtlQueueConfig {
    
    

    //普通交换机名称
    public static final  String X_EXCHANGE="X";
    //死信交换机名称
    public static final  String Y_DEAD_LETTER_EXCHANGE="Y";
    //普通队列名称
    public static final String QUEUE_A="A";
    public static final String QUEUE_B="B";
    public static final String QUEUE_C="C";
    //死信队列名称
    public static final String DEAD_LETTER_QUEUE="D";

    //声明交换机xExchange
    @Bean("xExchange")
    public DirectExchange xExchange(){
    
    
        return new DirectExchange(X_EXCHANGE);
    }

    //声明交换机yExchange
    @Bean("yExchange")
    public DirectExchange yExchange(){
    
    
        return new DirectExchange(Y_DEAD_LETTER_EXCHANGE);
    }

    //声明队列A
    @Bean("queueA")
    public Queue queueA(){
    
    
        Map<String,Object> arguments = new HashMap<>(3);
        //设置死信交换机
        arguments.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key","YD");
        //设置TTL,单位ms
        arguments.put("x-message-ttl",10000);
        return QueueBuilder.durable(QUEUE_A).withArguments(arguments).build();
    }

    //声明队列B
    @Bean("queueB")
    public Queue queueB(){
    
    
        Map<String,Object> arguments = new HashMap<>(3);
        //设置死信交换机
        arguments.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key","YD");
        //设置TTL,单位ms
        arguments.put("x-message-ttl",40000);
        return QueueBuilder.durable(QUEUE_B).withArguments(arguments).build();
    }

    //声明队列C
    @Bean("queueC")
    public Queue queueC(){
    
    
        Map<String,Object> arguments = new HashMap<>(2);
        //设置死信交换机
        arguments.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key","YD");
        return QueueBuilder.durable(QUEUE_C).withArguments(arguments).build();
    }

    //声明死信队列
    @Bean("queueD")
    public Queue queueD(){
    
    
        return QueueBuilder.durable(DEAD_LETTER_QUEUE).build();

    }

    //绑定A-X
    @Bean
    public Binding queueABindingX(@Qualifier("queueA") Queue queueA,
                                   @Qualifier("xExchange") DirectExchange xExchange ){
    
    
        return BindingBuilder.bind(queueA).to(xExchange).with("XA");
    }

    //绑定B-X
    @Bean
    public Binding queueBBindingX(@Qualifier("queueB") Queue queueB,
                                  @Qualifier("xExchange") DirectExchange xExchange ){
    
    
        return BindingBuilder.bind(queueB).to(xExchange).with("XB");
    }

    //绑定D-Y
    @Bean
    public Binding queueDBindingY(@Qualifier("queueD") Queue queueD,
                                  @Qualifier("yExchange") DirectExchange yExchange ){
    
    
        return BindingBuilder.bind(queueD).to(yExchange).with("YD");
    }

    //绑定C-X
    @Bean
    public Binding queueCBindingX(@Qualifier("queueC") Queue queueC,
                                  @Qualifier("xExchange") DirectExchange xExchange ){
    
    
        return BindingBuilder.bind(queueC).to(xExchange).with("XC");
    }
}

生产者代码

下面写消费者代码(controller层)
其中两个指定时长的延迟队列接口url后拼接生产消息的内容
指定时长的延迟队列接口url后拼接生产消息的内容以及延迟时间

@Slf4j
@RestController
@RequestMapping("/ttl")
public class SendMsgController {
    
    

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @GetMapping("/sendMsg/{message}")
    public void sendMsg(@PathVariable String message){
    
    

        log.info("当前时间:{},发送一条消息给两个TTL队列:{}",new Date().toString(),message);
        rabbitTemplate.convertAndSend("X","XA","消息来自ttl为10s的队列"+message);
        rabbitTemplate.convertAndSend("X","XB","消息来自ttl为40s的队列"+message);

    }
    //开始发消息,发消息+ttl
    @GetMapping("/sendExpirationMsg/{message}/{ttlTime}")
    public void sendMsg(@PathVariable String message,@PathVariable String ttlTime){
    
    
        log.info("当前时间:{},发送一条消息时长是{}毫秒TTL信息给队列C:{}",new Date().toString(),ttlTime,message);
        rabbitTemplate.convertAndSend("X","XC",message,msg->{
    
    
            //设置发送时的延迟时长
            msg.getMessageProperties().setExpiration(ttlTime);
            return  msg;
        });
    }
}

消费者代码

写消费者代码(监听)
注意,message等一定要导amqp的包

@Slf4j
@Component
public class DeadLetterQueueConsumer {
    
    

    //接收消息
    @RabbitListener(queues="D")
    public void receiveD(Message message, Channel channel)throws Exception{
    
    
        String msg = new String(message.getBody());
        log.info("当前时间:{},收到死信队列的消息:{}",new Date().toString(),msg);

    }
}

测试

到这里代码就已经写完了,下面开始用Postman测试
首先测试第一个接口,即固定时长的延迟队列
发送的内容为“固定时长的延迟队列”
在这里插入图片描述
首先生产者将信息发出
在这里插入图片描述
分别经过10s和40s:消费者接收到了对应的信息
在这里插入图片描述
这一项的测试完成

下面测试指定时长的延迟队列:
注意时长单位为ms,想要延时20s即为20000ms
在这里插入图片描述

首先生产者将信息发出在这里插入图片描述
经过20s:消费者接收到了信息
在这里插入图片描述
测试完成

扫描二维码关注公众号,回复: 14886109 查看本文章

同系列文章

原理部分

MQ(消息队列)简介
RabbitMQ简介
RabbitMQ 四大核心概念及工作原理

操作部分

Windows版Docker安装RabbitMq
Maven整合RabbitMQ实现生产消费消息
SpringBoot整合RabbitMQ实现生产消费消息
RabbitMQ发布确认-交换机确认
RabbitMQ-消息回报(队列确认)
RabbitMQ-备份交换机
RabbitMQ-优先级队列

猜你喜欢

转载自blog.csdn.net/m0_68681879/article/details/129547212