Definition: dead letter refers to messages that cannot be consumed. Dead letter queue is the queue for storing dead letters
Source: Message TTL expired, maximum queue length reached, message rejected
actual combat
One producer and two consumers (C1 and C2), and the producer passes normal of direct type_ Exchange (the bindingKey is zhangsan) publishes the message to the normal queue. C1 gets the message from the queue and consumes it normally. If the message in the normal queue is abnormal, it becomes a dead letter and passes through dead_exchange is sent to dead queue and processed by C2
Simulate ttl expiration
Turn on the producer but not the consumer, so that the messages released by the producer cannot be consumed. When the ttl expires, they will be sent to the dead letter queue through the dead letter switch
Consumer C1
Close immediately after startup (startup is to declare the common switch, common queue, dead letter switch and dead letter queue, bind the common queue and common switch (bind through bindingkey), dead letter queue and dead letter switch; Closing is to simulate that there is no consumer consumption message, and the expired message is sent to the dead letter queue)
package com.lin.rabbitmq.eight; import com.lin.rabbitmq.utils.RabbitMqUtils; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import java.util.HashMap; import java.util.Map; //Consumer C1 public class Consumer1 { public static final String NORMAL_EXCHANGE = "normal_exchange"; public static final String DEAD_EXCHANGE = "dead_exchange"; public static final String NORMAL_QUEUE = "normal_queue"; public static final String DEAD_QUEUE = "dead_queue"; public static void main(String[] args) throws Exception { Channel channel = RabbitMqUtils.getChannel(); //Declare dead letter and general switch channel.exchangeDeclare(NORMAL_EXCHANGE,BuiltinExchangeType.DIRECT); channel.exchangeDeclare(DEAD_EXCHANGE,BuiltinExchangeType.DIRECT); //Declare normal queue Map<String,Object> arguments =new HashMap<>( ); //Expiration time // arguments.put("x-message-ttl",10000); //Normal queue setting dead letter switch arguments.put("x-dead-letter-exchange",DEAD_EXCHANGE); //Set dead letter RoutingKey arguments.put("x-dead-letter-routing-key","lisi"); channel.queueDeclare(NORMAL_QUEUE,false,false,false,arguments); //Declare dead signal queue channel.queueDeclare(DEAD_QUEUE,false,false,false,null); //Binding common queue and common switch channel.queueBind(NORMAL_QUEUE,NORMAL_EXCHANGE,"zhangsan"); //bindingKey "zhangsan" //Bind dead letter queue and dead letter switch channel.queueBind(DEAD_QUEUE,DEAD_EXCHANGE,"lisi"); System.out.println("Waiting to receive message:"); DeliverCallback deliverCallback = (consumerTag,message)->{ System.out.println("Consumer1 The message received is:"+new String(message.getBody())); }; channel.basicConsume(NORMAL_QUEUE,true,deliverCallback,(consumerTag)->{}); } }
Producer
package com.lin.rabbitmq.eight; import com.lin.rabbitmq.utils.RabbitMqUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; //producer public class Producer { public static final String NORMAL_EXCHANGE = "normal_exchange"; public static void main(String[] args) throws Exception { Channel channel = RabbitMqUtils.getChannel(); //Setting TTL time for dead letter message AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build(); for(int i=1;i<=10;i++){ String message = "info"+i; channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",properties,message.getBytes()); } } }
Result display
normal_ In the Features column of the queue, ttl is the ttl expiration time we set in the Producer. DLX and DLK are abbreviations of x-dead-letter-exchange and x-dead-letter-routing-key
Consumer C2
Consumer C2 is used to consume messages in the dead letter queue, and the results are not displayed
package com.lin.rabbitmq.eight; import com.lin.rabbitmq.utils.RabbitMqUtils; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import java.util.HashMap; import java.util.Map; //Consumer C2 public class Consumer2 { public static final String DEAD_QUEUE = "dead_queue"; public static void main(String[] args) throws Exception { Channel channel = RabbitMqUtils.getChannel(); System.out.println("Waiting to receive message:"); DeliverCallback deliverCallback = (consumerTag,message)->{ System.out.println("Consumer2 The message received is:"+new String(message.getBody())); }; channel.basicConsume(DEAD_QUEUE,true,deliverCallback,(consumerTag)->{}); } }
The queue has reached its maximum length
First, remove the TTL attribute from the original producer code, and add the x-max-length attribute to consumer C1 and arguments
arguments.put("x-max-length",6);
Then delete the original normal in the rabbitmq web management interface_ Queue (the parameter is changed to avoid conflict), and then start consumer C1 as usual and close it immediately. It is found that
The producer sent 10 messages, but there was no consumer consumption because of normal_ The length of the queue is 6, so the remaining 4 messages are sent to the dead letter queue (no ttl time is set, so the messages in the normal_queue will not expire)
After that, open consumer C2 to consume the messages in the dead letter queue. The results are as follows. You can see that all messages in the dead letter queue have been consumed
Message rejected
First, comment out the argument of consumer C1 as usual Put ("x-max-length", 6), delete the common queue in the web management interface, and modify the consumption callback function of C1, as follows
DeliverCallback deliverCallback = (consumerTag,message)->{ String msg = new String(message.getBody()); if(msg.equals("info5")){ System.out.println("Consumer1 The message received is:"+msg+":This message was C1 Rejected"); channel.basicReject(message.getEnvelope().getDeliveryTag(),false); }else{ System.out.println("Consumer1 The message received is:"+msg); //Response message, false, do not start batch response channel.basicAck(message.getEnvelope().getDeliveryTag(),false); } };
Then start the manual response (the second parameter of the basicConsume method is changed to false)
Automatic response: after receiving the message, the consumer returns a response without processing it (calling the consumption callback function)
Manual response: the response is returned only after the processing is completed. You can respond in batches (multiple)
//Turn on manual answer channel.basicConsume(NORMAL_QUEUE,false,deliverCallback,(consumerTag)->{});
Result display
Only the rejected message 5 is sent to the dead letter queue, and then the message in the dead letter queue can be processed through consumer C2