RabbitMQ dead letter exchange never getting messages

rabbitmq retry with dead letter exchange
rabbitmq move messages from dead letter queue
rabbitmq exchange
rabbitmq requeue with delay
rabbitmq dead letter expiration
rabbitmq delayed message
pika dead letter-exchange
rabbitmq error handling

I'm trying to setup my first RabbitMQ dead letter exchange, here are the steps I'm using through the web admin interface:

  1. Create new DIRECT exchange with the name "dead.letter.test"
  2. Create new queue "dead.letter.queue"
  3. Bind "dead.letter.queue" to "dead.letter.test"
  4. Create new queue "test1" with the dead letter exchange set to "dead.letter.test"
  5. Send a message into "test1"
  6. Nack (with requeue = false) the message in "test1"

I am expecting that these steps should put a record into the "dead.letter.queue" through the "dead.letter.test" exchange. This is not happening.

I can manually put a message into the "dead.letter.test" exchange and it shows up in "dead.letter.queue" so I know that is fine.

When I look at the admin UI it shows that the DLX parameter is setup on the queue "test1".

Where am I going wrong?

Gentilissimo Signore was kind enough to answer my question on Twitter. The problem is that if your dead letter exchange is setup as DIRECT you must specify a dead letter routing key. If you just want all your NACKed message to go into a dead letter bucket for later investigation (as I do) then your dead letter exchange should be setup as a FANOUT.

Here are the updated steps that work:

  1. Create new FANOUT exchange with the name "dead.letter.test"
  2. Create new queue "dead.letter.queue"
  3. Bind "dead.letter.queue" to "dead.letter.test"
  4. Create new queue "test1" with the dead letter exchange set to "dead.letter.test"
  5. Send a message into "test1"
  6. Nack (with requeue = false) the message in "test1"

Dead Letter Exchanges, I have configured the Dead Letter Exchange (DLX) for RabbitMQ and You get the next message in the queue, and that's all you'll ever get. Note that expiration of a queue will not dead letter the messages in it. Dead letter exchanges (DLXs) are normal exchanges. They can be any of the usual types and are declared as usual. For any given queue, a DLX can be defined by clients using the queue's arguments, or in the server using policies.

Dead Letter Exchange without routing key and with direct exchange
Follow the steps these will work for sure:- 1. Create a new queue named 'dead_queue'. 2. Create an exchange named 'dead_exchange' and type of exchange should be 'direct'. 3. Bind 'dead_queue' and 'dead_exchange' without routing key. 4. Create a new queue named 'test_queue' and set its 'x-dead-letter-exchange' name as 'dead_exchange' 5. Create an exchange named 'test_exchange' and type of exchange should be 'direct' 6. Bind 'test_exchange' and 'test_queue' without routing key.

And at last we will check it. For this publish something on 'test_exchange' with argument 'expiration' set to 10000. After this when a message is publish on 'test_exchange' it will go to 'test_queue' and when a message is expired with in a queue it will look for DLX Parameter(Dead Letter Exchange name) there that message find the name 'dead_exchange' then that message will reach 'dead_exchange' deliver it to 'dead queue' .. If still you have any problem regarding this and if i miss understood your problem... write your problem i will surely look over it... Thanks..

Note: Must publish the message on 'test_exchange' because that test_queue and test_exchange binding is without routing key and it will work fine but If you publish message on 'test_queue' default exchange and routing key will be used.Then after expiration of message queue tries to deliver that dead message to dead_exchange with some default routing key and message will not go to that queue.

Dealing with Dead Letters and Poison Messages in RabbitMQ, RabbitMQ is a powerful, flexible message broker that is a great fit for many In the case of "poison" messages that can never successfully be processed, If there is a dead letter exchange, the message is routed there and if not, it gets binned. Dead Letter Exchange. Dropped messages are basically lost forever, unless you have defined a dead-letter exchange (dlx). This exchange is created to collect all dead letters and pass them into a special queue, which we named “all.dead-letters”. This queue is created manually, too, and just “stores” all the lost messages.

If you want to use custom routing key on dead letter exchange you have to set x-dead-letter-routing-key when declaring working queue (in your case it is test1), otherwise default routing key will be used. In your case RabbitMQ broker detects cycling and simply drop rejected messages.

What you need is to have x-dead-letter-exchange=dead.letter.test and x-dead-letter-routing-key=dead.letter.queue arguments set on test1 queue.

Handling Failure Successfully in RabbitMQ - IBM CODAIT, I recently dabbled with dead letter exchanges in rabbitmq 3.5.6 and With this config, it's widely accepted that a message rejected in "q.main" will never be To unsubscribe from this group and stop receiving emails from it,  However, there is no built-in poison message or dead-letter handling strategy in RabbitMQ. It provides the mechanism to recognize and isolate poison messages via dead-letter exchanges, but it does not give guidance or solutions on handling the messages one they are in the dead letter queue.

If you want all your queues to have same dead letter exchange it is easier to set a general policy:

sudo rabbitmqctl -p /my/vhost/path set_policy DLX ".*" '{"dead-letter-exchange":"MyExchange.DEAD"}' --apply-to queues

Dead-letter exchange and republishing to origin queue, This was our initial approach, every time a message fails, we just requeue it to consume it anymore, that way we never DDoS other services. Once you understand how RabbitMQ handles time to live ( TTL ) and dead-letter exchanges, the in Practice, you can use the discount code blog to get 10% off. The important thing to understand about messages that end up at the dead letter exchange is that they are routed in the normal way. These exchanges are not special, they can be declared in the usual way as direct, topic or fanout exchanges, and you bind queues to them in the normal way.

Don't need to create FANOUT exchange if it is not compulsory.

You can create DIRECT exchange using the same routing key which you have used already for other exchange. And also don't need to create a new queue for the new exchange. You can use existing queues with new exchange. You just need to bind that new exchange with the queue.

Here is my receive.js file:

var amqp = require("amqplib/callback_api");
var crontab = require('node-crontab');

amqp.connect("amqp://localhost", function (err, conn) {
conn.createChannel(function (err, ch) {
    var ex = 'direct_logs';
    var ex2 = 'dead-letter-test';
    var severity = 'enterprise-1-key';

    //assert "direct" exchange
    ch.assertExchange(ex, 'direct', { durable: true });
    //assert "dead-letter-test" exchange
    ch.assertExchange(ex2, 'direct', { durable: true });

    //if acknowledgement is nack() then message will be stored in second exchange i.e. ex2="dead-letter-test"
    ch.assertQueue('enterprise-11', { exclusive: false, deadLetterExchange: ex2 }, function (err, q) {
        var n = 0;
        console.log(' [*] Waiting for logs. To exit press CTRL+C');
        console.log(q);

        //Binding queue with "direct_logs" exchange
        ch.bindQueue(q.queue, ex, severity);
        //Binding the same queue with "dead-letter-test"
        ch.bindQueue(q.queue, ex2, severity);

        ch.consume(q.queue, function (msg) {
            // consume messages via "dead-letter-exchange" exchange at every second.
            if (msg.fields.exchange === ex2) {
                crontab.scheduleJob("* * * * * *", function () {
                    console.log("Received by latest exchange %s", msg.fields.routingKey, msg.content.toString());
                });
            } else {
                console.log("Received %s", msg.fields.routingKey, msg.content.toString());
            }

            if (n < 1) {
                // this will executes first time only. Here I'm sending nack() so message will be stored in "deadLetterExchange"
                ch.nack(msg, false, false);
                n += 1;
            } else {
                ch.ack(msg)
                n = 0
            }
        }, { noAck: false });
    });
  });
});

Exponential Backoff in RabbitMQ, MessageBus, handling dead letters in RabbitMQ to keep RabbitMQ resilient and stop losing relevant messages. We Are Apart but Stronger Than Ever. 8 Tips to Work From Home As soon they get alerted, they make sure that the backend team cleans up those invalid messages. To clean up that queue,  RabbitMQ dead letter exchange/queue. I don't quite understand the dead letter exchange/queue. the online document says: republished to another exchange when any of the following events occur: The message is rejected (basic.reject or basic.nack) with requeue=false, The TTL for the message expires; or The queue length limit is exceeded.

MessageBus – Dead-Letter-Exchange, What I hadn't found a need for was RabbitMQ's "Dead Letter Exchange" setup. Multiple times there had been discussions about using the dead letter pattern but I'd never gone that route. During one of my latest Next we get into the RabbitMQ config: An important item is deciding on a message converter, I'm a fan of the  RabbitMQ detects message flow cycling (E -> DLE -> E -> DLE ) and silently drops messages: From DLX manual (Routing Dead-Lettered Messages section): It is possible to form a cycle of dead-letter queues. For instance, this can happen when a queue dead-letters messages to the default exchange without specifiying a dead-letter routing key.

Spring, RabbitMQ & Dead Letter Exchanges, We know how to configure for optimal performance and how to get the most discarding messages from the head of the queue so that it never gets larger nacked or expired (with TTL) to the specified dead-letter-exchange. So when I send an invalid message and some exception occurs, it happens once (and it's good because previously message was sent over and over again) but the message doesn't go to my dead letter queue.

Part 1: RabbitMQ Best Practices, Use Dead Letter Exchange (DLX) and Dead Letter Routing Key (DLK) in You can get this tool from your RabbitMQ instance if you had  Unlike that flag, no basic.return s are issued, and if a dead letter exchange is set then messages will be dead-lettered. Per-Message TTL in Publishers. A TTL can be specified on a per-message basis, by setting the expiration field in the basic AMQP 0-9-1 class when sending a basic.publish.

Comments
  • What routing key are you using?
  • What if i want a dead letter queue with single exchange and redirect based on the route key . Is it possible with fanout ?
  • Solution to K-lyer's question: the only thing "special" about the dead letter exchange usage is that you bind it with the x-dead-letter-exchange and optional x-dead-letter-routing-key properties. If you want to redirect on a routing key just make it a direct exchange, and bind your queues to it.
  • Do you have any node js code for reference, I am trying to find where do I define the dead_exchange in publisher ? I already have set up a topic exchange.
  • @user269867 Sure, I will look into it. Because now a days I am working on node js. We can directly talk over skype sahil.gulati1991@outlook.com
  • Zaq, thanks for the response, I tried adding the x-dead-letter-exchange and the x-dead-letter-routing-key but I'm still not getting nacked messages to go into the dead letter exchange. My goal is simple: any message in the "test1" queue that is nacked will get put into the "dead.letter.test" exchange and then any queue that is attached to that exchange will receive the message. Do I need custom routing keys on the message to accomplish this?
  • Specify in question language and library you are using to deal with amqp broker. And add some code that reproduce your problem. Also specify RabbitMQ version.
  • In addition, setup Alternate Exchange, just in case your messages can't be routed. One of possible solution is to experiment on FANOUT exchange which definitely will rout message everywhere.
  • @jhilden did you solve you problem ? I have the same issue
  • I really recommend this approach as it far more flexible and the recommended approach from the rabbitmq team. I implemented both approaches and the policy one resulted in a lot less complex code and makes it very easy to dynamically change the behavior without backing up and recreating queues. See why you should use policies instead here: rabbitmq.com/parameters.html#policies
  • I've tried policies on both the exchange and queue level and messages never end up in my dead letter exchange, despite it working fine if I declare through arguments when declaring queue. I agree with ^^, this is a much nicer solution, not least because I don't have to redeclare/recreate/migrate queues when I want to update the policy.
  • Atul, the "test1" queue is not bound to any exchange, I'm just publishing directly to it for testing purposes. What I want is that when any message from "test1" is nacked that the message be put into the "dead.letter.test" exchange.
  • You will have to bind it to dead.letter.test. BTW how did you created queue without mentioning which exchange?