web-dev-qa-db-fra.com

L'échange de lettres mortes RabbitMQ ne reçoit jamais de messages

J'essaie de configurer mon premier échange de lettres mortes RabbitMQ, voici les étapes que j'utilise via l'interface d'administration Web:

  1. Créez un nouvel échange DIRECT avec le nom "dead.letter.test"
  2. Créer une nouvelle file d'attente "dead.letter.queue"
  3. Liez "dead.letter.queue" à "dead.letter.test"
  4. Créer une nouvelle file d'attente "test1" avec l'échange de lettres mortes défini sur "dead.letter.test"
  5. Envoyer un message dans "test1"
  6. Nack (avec requeue = false) le message dans "test1"

Je m'attends à ce que ces étapes mettent un enregistrement dans "dead.letter.queue" via l'échange "dead.letter.test". Cela n'arrive pas.

Je peux manuellement mettre un message dans l'échange "dead.letter.test" et il apparaît dans "dead.letter.queue" donc je sais que c'est très bien.

Lorsque je regarde l'interface utilisateur d'administration, cela montre que le paramètre DLX est configuré sur la file d'attente "test1".

Où vais-je mal?

42
jhilden

Gentilissimo Signore a eu la gentillesse de répondre à ma question sur Twitter. Le problème est que si votre échange de lettres mortes est configuré en DIRECT vous devez spécifier une clé de routage de lettres mortes. Si vous souhaitez simplement que tous vos messages NACK soient placés dans un seau de lettres mortes pour une enquête ultérieure (comme je le fais), votre échange de lettres mortes doit être configuré en tant que FANOUT.

Voici les étapes mises à jour qui fonctionnent:

  1. Créer un nouveau FANOUT échange avec le nom "dead.letter.test"
  2. Créer une nouvelle file d'attente "dead.letter.queue"
  3. Liez "dead.letter.queue" à "dead.letter.test"
  4. Créer une nouvelle file d'attente "test1" avec l'échange de lettres mortes défini sur "dead.letter.test"
  5. Envoyer un message dans "test1"
  6. Nack (avec requeue = false) le message dans "test1"
59
jhilden

Dead Letter Exchange sans clé de routage et avec échange direct



dead_queue
dead_exchange
dead_queuedead_exchange
test_queuex-dead-letter-exchangedead_exchange
test_exchange
test_exchangetest_queue

Et enfin nous allons le vérifier. Pour cela, publiez quelque chose sur 'test_exchange"avec argument"expiration"défini sur 10000. Après cela, lorsqu'un message est publié sur"test_exchange"ça ira"test_queue"et lorsqu'un message arrive à expiration dans une file d'attente, il recherche le paramètre DLX (nom Dead Letter Exchange) dans lequel ce message trouve le nom"dead_exchange"alors ce message atteindra"dead_exchange"livrer à"file d'attente morte'.. Si vous avez toujours un problème à ce sujet et si je ne comprends pas votre problème ... écrivez votre problème, je vais sûrement l'examiner ... Merci ..

Remarque: Doit publier le message sur 'test_exchange"car cette liaison test_queue et test_exchange est sans clé de routage et cela fonctionnera bien mais si vous publiez un message sur"test_queue'la clé d'échange et de routage par défaut sera utilisée.Après l'expiration de la file d'attente de messages, il tentera de remettre ce message mort à dead_exchange avec une clé de routage par défaut et le message n'ira pas dans cette file d'attente.

12
Sahil Gulati

Si vous souhaitez utiliser une clé de routage personnalisée sur l'échange de lettres mortes, vous devez définir x-dead-letter-routing-key lors de la déclaration de la file d'attente de travail (dans votre cas, c'est test1), sinon la clé de routage par défaut sera utilisée. Dans votre cas, le courtier RabbitMQ détecte le cyclage et laisse simplement tomber les messages rejetés.

Ce dont vous avez besoin, c'est d'avoir x-dead-letter-exchange=dead.letter.test et x-dead-letter-routing-key=dead.letter.queue arguments définis sur test1 file d'attente.

6
pinepain

Si vous souhaitez que toutes vos files d'attente aient le même échange de lettres mortes, il est plus facile de définir une stratégie générale:

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

Pas besoin de créer un échange FANOUT s'il n'est pas obligatoire.

Vous pouvez créer un échange DIRECT en utilisant la même clé de routage que vous avez déjà utilisée pour un autre échange. Et pas besoin non plus de créer une nouvelle file d'attente pour le nouvel échange. Vous pouvez utiliser les files d'attente existantes avec un nouvel échange. Vous avez juste besoin de lier ce nouvel échange à la file d'attente.

Voici mon fichier 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
Jay Sojitra

Créer un nouvel échange DIRECT avec le nom "dead.letter.test"

Correct

Créer une nouvelle file d'attente "dead.letter.queue"

Correct

Liez "dead.letter.queue" à "dead.letter.test"

Correct

Créer une nouvelle file d'attente "test1" avec l'échange de lettres mortes défini sur "dead.letter.test"

Je suppose que vous créez la file d'attente test1 et la liez à l'échange dead.letter.test

Envoyer un message dans "test1"

Si vous souhaitez que votre message soit reçu par dead.letter.queue, vous devrez fournir une clé de routage lors de l'envoi du message et les clients consommant dead.letter.queue doivent également utiliser la même clé de routage

Si vous publiez sans clé de routage, seuls les clients abonnés à test1 recevront le message.

Si vous publiez un message sur l'échange direct.letter.test, alors toute la file d'attente recevra le message. Cela fonctionnera comme un échange de fanout

Donc, si vous souhaitez que dead.letter.queue reçoive un message, vous devrez publier le message dans cette file d'attente ou vous devrez utiliser la même clé de routage lors de la publication et de l'abonnement et publier le message à échanger.

2
Jack Daniel's