Implement rabbitmq delay queue function

 Recently, in the research of rabbitmq, there is such a scenario in the project: when the user wants to pay for the order, if the payment is not made for more than 30 minutes, the order will be closed. Of course, we can do a scheduled task to scan unpaid orders every period of time. If the order exceeds the payment time, it will be closed. However, when the amount of data is small, there is no big problem, but the amount of data is large. method becomes particularly resource-intensive. When facing the data volume of tens of millions or hundreds of millions, the IO written by itself is relatively high, which leads to long-term queries or cannot be found at all, let alone after sub-database and sub-table. In addition, there are priority queues, JDK delay queues based on priority queues, time wheels and other methods. But if there is RabbitMQ in the architecture of the system, then choosing RabbitMQ to achieve similar functions is also an option. We use rabbitmq in our project, which can perfectly solve this problem by making a delay queue.

     Rabbitmq itself does not have the function of delaying message queues, but it can be implemented through the features of TTL (Time To Live) and DLX (Dead Letter Exchanges). The principle is to set the expiration time for the message, and specify the forwarder for the expired message on the message queue, so that after the message expires, it will be forwarded to the queue that matches the specified forwarder, and the direction of the delay queue is realized. Using this feature of rabbitmq, there should be a general idea. ,

I searched the Internet for the   rabbitmq-delayed-message-exchange  plugin, which can also implement the function of delayed queue. Today I will introduce how to use C# to achieve it.

First look at TTL and DLX 

TTL (Time To Live) of the message

The TTL of a message is the time-to-live of the message. RabbitMQ can set TTL separately for queues and messages. The setting for the queue is the retention time of the queue without consumer connection, and it can also be set separately for each individual message. After this time, we consider the message dead, and call it a dead letter. If the queue is set and the message is set, it will be smaller. So if a message is routed to different queues, the time of death of the message may be different (different queue settings). Here we only talk about the TTL of a single message, because it is the key to realizing the delay task.

Dead Letter Exchanges

The concept of Exchage will not be repeated here. A message will enter the dead letter route if it meets the following conditions. Remember that this is a route, not a queue. A route can correspond to many queues.

1. A message was rejected by the Consumer, and the requeue parameter of the reject method is false. That is to say, it will not be placed in the queue again and used by other consumers.

2. The TTL of the above message has arrived, and the message has expired.

3. The length limit of the queue is full. Messages in the front of the queue are discarded or thrown on the dead letter route.

Dead Letter Exchange is actually an ordinary exchange, no different from creating other exchanges. It's just that a message expires in a queue where Dead Letter Exchange is set, and it will automatically trigger the forwarding of the message and send it to Dead Letter Exchange.

 First, I built two console projects, one is a producer and the other is a consumer.

The producer code is as follows 

copy code
            var factory = new ConnectionFactory() { HostName = "127.0.0.1", UserName = "test", Password = "test" };
            using (var connection = factory.CreateConnection())
            {
                while (Console.ReadLine() != null)
                {
                    using (var channel = connection.CreateModel())
                    {

                        Dictionary<string, object> dic = new Dictionary<string, object>();
                        dic.Add("x-expires", 30000);
                        dic.Add("x-message-ttl", 12000);//The message expiration time on the queue should be less than the queue expiration time  
                        dic.Add("x-dead-letter-exchange", "exchange-direct");//The expired message is redirected to the route  
                        dic.Add("x-dead-letter-routing-key", "routing-delay");//The expired message turns to the routing matching routingkey  
                        //Create a message queue named "zzhello"
                        channel.QueueDeclare(queue: "zzhello",
                            durable: true,
                            exclusive: false,
                            autoDelete: false,
                            arguments: dic);

                        var message = "Hello World!";
                        var body = Encoding.UTF8.GetBytes(message);

                        //Send message to the message queue
                        channel.BasicPublish(exchange: "",
                            routingKey: "zzhello",
                            basicProperties: null,
                            body: body);
                        Console.WriteLine(" [x] Sent {0}", message);
                    }
                }
            }

            Console.ReadKey();
copy code

The consumer code is as follows:

 

copy code
var factory = new ConnectionFactory() { HostName = "127.0.01", UserName = "test", Password = "test" };

            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(exchange: "exchange-direct", type: "direct");
                    string name = channel.QueueDeclare().QueueName;
                    channel.QueueBind(queue: name, exchange: "exchange-direct", routingKey: "routing-delay");

                    //Callback, this function will be executed when the consumer receives the message
                    var consumer = new EventingBasicConsumer(channel);
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body;
                        var message = Encoding.UTF8.GetString(body);
                        Console.WriteLine(ea.RoutingKey);
                        Console.WriteLine(" [x] Received {0}", message);
                    };

                    //Console.WriteLine("name:" + name);
                    //Consume the message in the queue "hello"
                    channel.BasicConsume(queue: name,
                                         autoAck: true,
                                         consumer: consumer);

                    Console.WriteLine(" Press [enter] to exit.");
                    Console.ReadLine();
                }
            }

            Console.ReadKey();
copy code

 

  

Effect:

The consumer waited for the message after waiting 12 seconds.

 

 In this way, we have realized the function of delay queue.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324736355&siteId=291194637