- delay queue
RabbitMQ itself does not have the function of delayed message queue, but it can be implemented through TTL (Time To Live) and DLX (Dead Letter Exchanges) features. 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, it should be possible to realize many real-world businesses, and we can use our imagination.
rabbitmq-delayed-message-exchange , we can also use plugins to implement delayed queues. Can the delay queue implemented by TTL and DLX be interrupted, can the delay queue implemented by using plugins be interrupted? Save for next time. . .
- Points to Note
Set an expiration time for each message :
Builder properties=new BasicProperties.Builder(); //The specified message expiration time is 12 seconds, and the message expiration time can also be specified on the queue, whichever is smaller. properties.expiration("12000");//Delayed for 12 seconds, it will not be deleted in time (it is determined whether it expires when consumemr is consumed, because the expiration time of each message is inconsistent, deleting expired messages requires scanning the entire queue) channel.basicPublish("header_exchange", "" ,properties.build(), SerializationUtils.serialize(object));
Set the queue expiration time (you can not set it), message expiration time, and expired message forwarding rules on the queue :
//Set the message expiration time to 12 seconds, and forward the message to the specified forwarder and matching routingkey when the message expires (can not be specified) Map<String, Object> args=new HashMap<String, Object>(); args.put("x-expires", 30000);//Queue expiration time args.put("x-message-ttl", 12000);//The message expiration time on the queue should be less than the queue expiration time args.put("x-dead-letter-exchange", "exchange-direct");//The expired message is redirected to the route args.put("x-dead-letter-routing-key", "routing-delay");//The expired message redirects to the route matching the routingkey
The message will expire without consumer consumption, so the consumer in the receiving message class needs to comment out
the message expiration time set on the queue and the message expiration time set on the message. The priority is the smaller
. Set the message expiration time on the queue and set the message on the message. Expiration time, the latter expired messages may not be deleted in time, because the expiration time of each message is inconsistent, and deleting expired messages requires scanning the entire queue, so it is judged whether it expires when consuming
- send message class
package com.demo.mq.rabbitmq.example08; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.SerializationUtils; import com.demo.mq.rabbitmq.MqManager; import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.AMQP.BasicProperties.Builder; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * Send message class * @author sheungxin * */ public class Send{ /** * Practice delayed forwarding on the basis of topic forwarders, and specify message expiration time when sending messages * The message has been sent to the queue, but not consumed by the consumer * @param object message body * @throws IOException */ public static void sendAToB(Serializable object) throws Exception{ Connection conn=MqManager.newConnection(); Channel channel=conn.createChannel(); //declare the headers forwarder channel.exchangeDeclare("header_exchange", BuiltinExchangeType.HEADERS); //Define the key-value pair stored by headers Map<String, Object> headers=new HashMap<String, Object>(); headers.put("key", "123456"); headers.put("token", "654321"); // put the key-value pair in properties Builder properties=new BasicProperties.Builder(); properties.headers(headers); properties.deliveryMode(2);//Persistence //The specified message expiration time is 12 seconds, and the message expiration time can also be specified on the queue, whichever is smaller. // properties.expiration("12000");//Delayed for 12 seconds, it will not be deleted in time (it is determined whether it has expired when consuming consumemr, because the expiration time of each message is inconsistent, deleting expired messages requires scanning the entire queue) channel.basicPublish("header_exchange", "" ,properties.build(), SerializationUtils.serialize(object)); System.out.println("Send '"+object+"'"); channel.close(); conn.close(); } public static void main(String[] args) throws Exception { sendAToB("Hello World !"); } }
- receive message class
package com.demo.mq.rabbitmq.example08; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.SerializationUtils; import com.demo.mq.rabbitmq.MqManager; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Consumer; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * Receive message class * @author sheungxin * */ public class Recv { /** * Practice delayed forwarding on the basis of topic forwarders, set queue expiration time (automatically delete after expiration), and expire message processing strategy (forward to matching queue) * After starting the receiving class to create the queue during the experiment, close the thread and make it into an unused state * @throws Exception */ public static void recvAToB() throws Exception{ Connection conn=MqManager.newConnection(); Channel channel=conn.createChannel(); channel.exchangeDeclare("header_exchange", BuiltinExchangeType.HEADERS); //Set the queue expiration time to 30 seconds, and forward the message to the specified forwarder and the matching routingkey when the message expires (can not be specified) Map<String, Object> args=new HashMap<String, Object>(); args.put("x-expires", 30000);//Queue expiration time args.put("x-message-ttl", 12000);//The message expiration time on the queue args.put("x-dead-letter-exchange", "exchange-direct");//The expired message is redirected to the route args.put("x-dead-letter-routing-key", "routing-delay");//The expired message redirects to the route matching the routingkey //create a temporary queue String queueName=channel.queueDeclare("tmp01",false,false,false,args).getQueue(); //Specify the matching type of headers (all, any), key-value pair Map<String, Object> headers=new HashMap<String, Object>(); headers.put("x-match", "all");//all any (as long as there is a key-value pair matching) headers.put("key", "123456"); // headers.put("token", "6543211"); //Bind the temporary queue and forwarder header_exchange channel.queueBind(queueName, "header_exchange", "", headers); System.out.println("Received ..."); Consumer consumer=new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{ String mes=SerializationUtils.deserialize(body); System.out.println(envelope.getRoutingKey()+":Received :'"+mes+"' done"); channel.basicAck(envelope.getDeliveryTag(), false); } }; //Turn off the automatic response mechanism, which is enabled by default; at this time, you need to manually perform the response channel.basicConsume(queueName, false, consumer); } public static void main(String[] args) throws Exception { recvAToB (); } }
- Delayed message processing class
package com.demo.mq.rabbitmq.example08; import java.io.IOException; import org.apache.commons.lang3.SerializationUtils; import com.demo.mq.rabbitmq.MqManager; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Consumer; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * Delayed message processing class * @author sheungxin * */ public class DelayRecv { /** * Create a queue and declare that the consumer is used to process the forwarded delayed messages * @throws Exception */ public static void delayRecv() throws Exception{ Connection conn=MqManager.newConnection(); Channel channel=conn.createChannel(); channel.exchangeDeclare("exchange-direct", BuiltinExchangeType.DIRECT); String queueName=channel.queueDeclare().getQueue(); channel.queueBind(queueName, "exchange-direct", "routing-delay"); Consumer consumer=new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{ String mes=SerializationUtils.deserialize(body); System.out.println(envelope.getRoutingKey()+":delay Received :'"+mes+"' done"); } }; //Turn off the automatic response mechanism, which is enabled by default; at this time, you need to manually perform the response channel.basicConsume(queueName, true, consumer); } public static void main(String[] args) throws Exception { delayRecv(); } }