Recently, in the study of RABBITMQ, the project had a scenario where the order would be closed if the user had to pay for more than 30 minutes. Of course, we can do a timed task, each time to scan the unpaid orders, if the order is more than the payment time off, but there is no big problem when the volume of data is small, but the data volume of a large rotation database will become a special resource consumption. When faced with tens, billions of levels of data, its own write Io is relatively high, resulting in long-time queries or simply can not find out, let alone the sub-database after the table. In addition to this, there are priority queues, JDK delay queues based on priority queues, and time-wheel methods. But if the architecture of the system itself has RABBITMQ, then choosing RABBITMQ to implement similar functionality is also an option. We used the RABBITMQ in the project and could do a delay queue to solve the problem perfectly.
The RABBITMQ itself does not have the ability to delay Message Queuing, but it can be implemented with TTL (time to Live), DLX (Dead-letter exchanges) features. Its principle sets the expiration time for the message, specifies the forwarder for the expired message on the message queue, so that the message expires and forwards to the queue that matches the specified forwarder, to implement the deferred queue. Using this characteristic of RABBITMQ, there should be an approximate idea. 、
Search the Internet. rabbitmq-delayed-message-exchange This plugin can also implement the function of delay queue. Today's introduction is how to implement it in C #.
First look at the TTL and DLX
TTL of messages (time to Live)
The TTL of a message is the time the message is alive. RABBITMQ can set the TTL for queues and messages individually. A queue setting is a queue that has no customer-attached retention time, or a separate setting for each individual message. Over this time, we think the news is dead, called Dead letter. If the queue is set and the message is set, it will take small. So if a message is routed to a different queue, the message may not be the same as the time it was killed (different queue settings). This is where the TTL of a single message is spoken, because it is the key to implementing the deferred task.
Dead Letter Exchanges
The concept of exchage is not to be mentioned here. A message will enter a dead-letter route If the following conditions are met, remembering that this is a route rather than a queue, and that a route can correspond to many queues.
1. A message was rejected by consumer, and Requeue is false in the parameters of the Reject method. This means that it will not be placed in the queue again and used by other consumers.
2. The TTL of the above message is up, and the message expires.
3. The queue length limit is full. Messages that are in front of you are discarded or thrown on a dead-letter route.
Dead Letter Exchange is actually a common exchange, and it's no different than creating other exchange. Only a message that has expired in a queue of one of the settings dead Letter Exchange will automatically trigger the forwarding of messages to dead letter exchange.
First, I built two console projects. One is the producer and the other is the consumer.
The producer code is as follows
var factory = new ConnectionFactory () {HostName = "127.0.0.1", UserName = "Test", Password = "Test"}; using (var connection = factory. CreateConnection ()) {while (Console.ReadLine ()! = null) {USI Ng (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");//Expired messages are diverted to route DIC. ADD ("X-dead-letter-routing-key", "Routing-delay");//expiration message to route match Routingkey//create a message queue called "Zzhello" Channel. Queuedeclare (queue: "Zzhello", Durable:true, Exclusive:false, AutodelEte:false, Arguments:dic); var message = "Hello world!"; var BODY = Encoding.UTF8.GetBytes (message); Sends messages to the message Queue message channel. Basicpublish (Exchange: "", Routingkey: "Zzhello", basicproperties:n Ull, Body:body); Console.WriteLine ("[x] Sent {0}", message); }}} Console.readkey ();
The consumer code is as follows:
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, which executes the function when 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); The message channel in the consumption queue "Hello". Basicconsume (Queue:name, Autoack:true, C Onsumer:consumer); Console.WriteLine ("Press [Enter] to exit."); Console.ReadLine (); }} console.readkey ();
Effect:
After waiting for 12 seconds, the consumer waits for the message.
This allows us to implement the delay queue function.
C # implements the RABBITMQ delay queue feature