首页 文章

RabbitMQ死信交换永远不会得到消息

提问于
浏览
39

我正在尝试设置我的第一个RabbitMQ死信交换,这是我通过Web管理界面使用的步骤:

  • 使用名称"dead.letter.test"创建新的DIRECT交换

  • 创建新队列"dead.letter.queue"

  • 绑定"dead.letter.queue"至"dead.letter.test"

  • 创建新队列"test1",并将死信交换设置为"dead.letter.test"

  • 发送消息至"test1"

  • Nack(带有requeue = false)"test1"中的消息

我期待这些步骤应该通过“dead.letter.test”交换记录到“dead.letter.queue” . 这不会发生 .

我可以手动将消息放入“dead.letter.test”交换中,它显示在“dead.letter.queue”中,所以我知道这很好 .

当我查看管理UI时,它显示在队列“test1”上设置了DLX参数 .

我哪里错了?

6 回答

  • 51

    Gentilissimo Signore非常友好地在Twitter上回答我的问题 . 问题是,如果您的死信交换设置为DIRECT,则 must 指定死信路由密钥 . 如果您只是希望所有NACKed消息进入死信桶以供以后调查(就像我一样)那么您的死信交换应设置为FANOUT .

    以下是有效的更新步骤:

    • 使用名称"dead.letter.test"创建新的 FANOUT 交换

    • 创建新队列"dead.letter.queue"

    • 绑定"dead.letter.queue"至"dead.letter.test"

    • 创建新队列"test1",并将死信交换设置为"dead.letter.test"

    • 发送消息至"test1"

    • Nack(带有requeue = false)"test1"中的消息

  • 6

    死信交换没有路由密钥和直接交换

    按照以下步骤进行操作: -
    1.创建名为“ dead_queue ”的新队列 .
    2.创建名为' dead_exchange ' and type of exchange should be ' direct'的交易所 .
    3.绑定' dead_queue ' and ' dead_exchange ',不带路由密钥 .
    4.创建名为“ test_queue ' and set its ' x-dead-letter-exchange ' name as ' dead_exchange ”的新队列
    5.创建一个名为' test_exchange ' and type of exchange should be ' direct'的交易所
    6.在没有路由键的情况下绑定' test_exchange ' and ' test_queue ' .

    最后我们将检查它 . 对于这个发布的东西' 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 '..如果你仍然有任何问题,如果我错过了解你的问题...写下你的问题我一定会看看它 . .. 谢谢..

    Note: 必须在' 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 '上发布消息,将使用默认交换和路由密钥 . 然后在消息队列到期后尝试使用某个默认路由密钥将该死信消息传递给dead_exchange,并且消息将不会转到该队列 .

  • 2

    如果要在死信交换上使用自定义路由密钥,则必须在声明工作队列时设置 x-dead-letter-routing-key (在您的情况下为 test1 ),否则将使用默认路由密钥 . 在您的情况下,RabbitMQ代理检测循环并简单地丢弃被拒绝的消息 .

    你需要的是在 test1 队列上设置 x-dead-letter-exchange=dead.letter.testx-dead-letter-routing-key=dead.letter.queue 参数 .

  • 9

    如果您希望所有队列都具有相同的死信交换,则更容易设置一般策略:

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

    如果不是强制性的,则不需要创建FANOUT交换 .

    您可以使用已用于其他交换的相同路由密钥创建DIRECT交换 . 并且也不需要为新交换创建新队列 . 您可以使用现有队列进行新交换 . 您只需要将新交换绑定到队列 .

    这是我的receive.js文件:

    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 });
        });
      });
    });
    
  • 3

    使用名称“dead.letter.test”创建新的DIRECT交换

    正确

    创建新队列“dead.letter.queue”

    正确

    将“dead.letter.queue”绑定到“dead.letter.test”

    正确

    创建新的队列“test1”,将死信交换设置为“dead.letter.test”

    我假设您正在创建test1队列并将其绑定到dead.letter.test exchange

    发送消息到“test1”

    如果你希望你的消息被dead.letter.queue收到,你必须在发送消息时提供路由密钥,而使用dead.letter.queue的客户端也应该使用相同的路由密钥

    如果您在没有路由密钥的情况下发布,那么只有订阅了test1的客户才会收到该消息 .

    如果您将消息发布到direct.letter.test exchange,则所有队列都将收到该消息 . 它会像一个扇出交换

    因此,如果您希望dead.letter.queue接收消息,您将不得不在该队列中发布消息,或者您必须在发布和订阅时使用相同的路由密钥并将消息发布到交换

相关问题