RabbitMQ delay queue and actual combat

delay queue

A delay queue is a queue in which messages entering the queue will be delayed for consumption. For general queues, once a message is enqueued, it will be consumed immediately by consumers

Delay queues are mostly used in scenarios that require delayed work.
If the safety work order has not been processed within 24 hours, it will automatically pull the enterprise group to remind the relevant responsible person.
After the user places an order for food delivery, when there are 10 minutes before the timeout, the delivery boy will be reminded that the timeout is about to expire.
Delayed consumption:
After the user generates an order, it takes a period of time to verify the payment status of the order. If the order is still unpaid, the order needs to be closed in time.
After the user registration is successful, it will take a period of time, such as a week, to verify the user's usage. If the user's activity is found to be low, an email or text message will be sent to remind the user to use it.
Delayed retry:
For example, the consumer fails to consume messages from the queue, but wants to automatically retry after a delay.

project structure

insert image description here
As shown in the figure:
p: Producer
C: Consumer
X, Y are directly connected switches, where Y is a dead letter switch
AD is a queue, where A, B are delay queues for a fixed time, C is a delay queue for a specified duration, and D is dead letter queue

Integrating RabbitMq in SpringBoot

add dependencies

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

configuration file

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

Configuration class code

Create a new configuration class below, declare queues, switches, and bind them

/**
 * 延迟队列+死信队列配置类
 */
@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");
    }
}

producer code

Write the consumer code (controller layer) below,
in which the content of the production message is spliced ​​after two specified delay queue interface urls.
The content of the production message and the delay time are spliced ​​after the specified duration of the delay queue interface 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;
        });
    }
}

consumer code

Write consumer code (monitoring)
Note, message and so on must lead to amqp package

@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);

    }
}

test

The code has been written here, let’s start
testing with Postman First test the first interface, that is, the fixed-length delay queue. The content sent
is "fixed-time delay queue" . The tester has received the corresponding information. The test of this item is completed.
insert image description here

insert image description here

insert image description here

The following tests the delay queue with a specified duration:
Note that the duration unit is ms, and if you want to delay for 20s, it is 20000ms
insert image description here

First, the producer sends out the information insert image description here
and after 20s: the consumer receives the information
insert image description here
and the test is completed

Articles in the same series

Principle part

Introduction to MQ (message queue) Introduction
to RabbitMQ Introduction to
RabbitMQ Four core concepts and working principles

Operating part

Install RabbitMq on Windows version of Docker
Maven integrates RabbitMQ to realize production and consumption of messages SpringBoot
integrates RabbitMQ to realize production
and consumption
of messages

Guess you like

Origin blog.csdn.net/m0_68681879/article/details/129547212