web-dev-qa-db-fra.com

Comment remettre en file d'attente des messages dans RabbitMQ

Une fois que le consommateur a reçu un message, le consommateur/travailleur effectue certaines validations, puis appelle le service Web. Dans cette phase, si une erreur se produit ou si la validation échoue, nous voulons que le message soit remis dans la file d'attente à partir de laquelle il a été consommé à l'origine.

J'ai lu la documentation de RabbitMQ. Mais je suis confus quant aux différences entre les méthodes de rejet, de nack et d'annulation.

27
yunus kula

Réponse courte:

Pour remettre en file d'attente un message spécifique, vous pouvez choisir à la fois basic.reject Ou basic.nack Avec l'indicateur multiple défini sur false.

L'appel de basic.consume Peut également entraîner la redistribution des messages si vous utilisez l'accusé de réception de message et qu'il y a un message non acquitté sur le consommateur à un moment précis et qu'il quitte sans l'acquitter.

basic.recover Retransmettra tous les messages non acquittés sur un canal spécifique.

Réponse longue:

basic.reject et basic.nack les deux ont le même objectif - supprimer ou remettre en file d'attente un message qui ne peut pas être géré par un consommateur spécifique (à la date indiquée) moment, sous certaines conditions ou pas du tout). La principale différence entre eux est que basic.nack Prend en charge le traitement des messages en masse, contrairement à basic.reject.

Cette différence décrite dans Remerciements négatifs article sur le site Web officiel de RabbitMQ:

La spécification AMQP définit la méthode basic.reject Qui permet aux clients de rejeter les messages individuels remis, en demandant au courtier de les supprimer ou de les remettre en file d'attente. Malheureusement, basic.reject Ne prend pas en charge la reconnaissance négative des messages en masse.

Pour résoudre ce problème, RabbitMQ prend en charge la méthode basic.nack Qui fournit toutes les fonctionnalités de basic.reject Tandis que permet également un traitement en masse des messages .

Pour rejeter les messages en bloc, les clients définissent l'indicateur multiple de la méthode basic.nack Sur true. Le courtier rejettera ensuite tous les messages non acquittés et remis jusqu'au message inclus dans le champ delivery_tag De la méthode basic.nack. À cet égard, basic.nack complète la sémantique d'accusé de réception en masse de basic.ack .

Notez que la méthode basic.nack Est une extension spécifique à RabbitMQ tandis que la méthode basic.reject Fait partie de la spécification AMQP 0.9.1.

Quant à la méthode basic.cancel , elle avait l'habitude d'aviser le serveur que le client arrêtait de consommer des messages. Notez que ce client peut recevoir un nombre arbitraire de messages entre la méthode basic.cancel Et l'envoi de la réponse cancel-ok. Si l'accusé de réception de message est utilisé par le client et qu'il contient des messages non acquittés, ils seront replacés dans la file d'attente à partir de laquelle ils ont été consommés à l'origine.

basic.recover a quelques limitations dans RabbitMQ: il - basic.recover avec requeue = false - basic.recover synchronicity

En plus des errata, selon les spécifications de RabbitMQbasic.recover A un support partiel (La récupération avec requeue = false n'est pas supportée.)

Remarque sur basic.consume :

Lorsque basic.consume a démarré sans acquittement automatique (no­ack=false) Et qu'il y a des messages en attente des messages non acquittés, puis lorsque le consommateur est annulé (meurt, erreur fatale, exception , peu importe) que les messages en attente seront redistribués. Techniquement, les messages en attente ne seront pas traités (même les lettres mortes) jusqu'à ce que le consommateur les libère (ack/nack/rejet/récupération). Ce n'est qu'après cela qu'ils seront traités (par exemple, en lettre morte).

Par exemple, supposons que nous publions à l'origine 5 messages consécutifs:

Queue(main) (tail) { [4] [3] [2] [1] [0] } (head)

Et puis consommer 3 d'entre eux, mais pas les acquitter, puis annuler le consommateur. Nous aurons cette situation:

Queue(main) (tail) { [4] [3] [2*] [1*] [0*] } (head)

où star (*) note que l'indicateur redelivered est défini sur true.

Supposons que nous ayons une situation avec un ensemble d'échange de lettres mortes et une file d'attente pour les messages de lettres mortes

Exchange(e-main)                                   Exchange(e-dead) 
  Queue(main){x-dead-letter-exchange: "e-dead"}       Queue(dead) 

Et supposons que nous publions 5 messages avec la propriété expire définie sur 5000 (5 sec):

Queue(main) (tail) { [4] [3] [2] [1] [0] } (head)
Queue(dead) (tail) { }(head)

puis nous consommons 3 messages de la file d'attente main et les maintenons pendant 10 secondes:

Queue(main) (tail) { [2!] [1!] [0!] } (head)
Queue(dead) (tail) { [4*] [3*] } (head)

où le point d'exclamation (!) représente le message non empilé. Ces messages ne peuvent être livrés à aucun consommateur et ils ne peuvent normalement pas être affichés dans le panneau de gestion. Mais annulons le consommateur, rappelez-vous, qu'il contient toujours 3 messages non confirmés:

Queue(main) (tail) { } (head)
Queue(dead) (tail) { [2*] [1*] [0*] [4*] [3*] } (head)

Alors maintenant que 3 messages qui étaient dans la tête sont remis dans la file d'attente d'origine, mais comme ils ont par message TTL défini, ils sont en lettres mortes à la fin de la file d'attente des lettres mortes (bien sûr , via échange de lettres mortes).

P.S.:

Consommer un message aka écouter un nouveau est en quelque sorte différent de l'accès direct à la file d'attente (obtenir un ou plusieurs messages sans prendre soin des autres). Voir basic.get description de la méthode pour en savoir plus.

53
pinepain