RabbitMQ subscriber sending message back onto RabbitMQ queue? - node.js

I would appreciate your thoughts on this.
I have a node app which subscribes to a RabbitMQ queue. When it receives a message, it checks it for something and then saves it to a database.
However, if the message is missing some information or some other criteria is not yet met, I would like the subscriber to publish the message back onto the RabbitMQ queue.
I understand logically this is just connecting to the queue and publishing the message, but is it really this simple or is this a bad practice or potentially dangerous?
Thanks for your help.

As I point out in the comment, When you create connection with queue, and set autoAck = true, to enable message acknowledge. The message in the queue will be deleted until receive acknowledge.
When the received message meets requirement, then send ack message to this queue, and this message will be deleted from queue. Otherwise, no ack message is sent to queue, this message will stay in the queue.
As for you mentioned in comment, the valid process may take 5 minutes, just set the send ack message as callback function of validation function.

In your question, you describe two criterion for when a message may not be processed:
if the message is missing some information or
some other criteria is not yet met
The first of these appears to be an issue with the message, and it doesn't seem that it makes much sense to re-queue a message that has a problem. The appropriate action is to log an error and drop the message (or invoke whatever error-handling logic your application contains).
The second of these is rather vague, but for the purposes of this answer, we will assume that the problem is not with the message but with some other component in the system (e.g. perhaps a network connection issue). In this case, the consuming application can send a Nack (negative acknowldegement) which can optionally requeue the message.
Keep in mind that in the second case, it will be necessary to shut down the consumer until the error condition has resolved, or the message will be redelivered and erroneously processed ad infinitum until the system is back up, thus wasting resources on an unprocessable message.
Why use a nack instead of simply re-publishing?
This will set the "redelivered" flag on the message so that you know it was delivered once already. There are other options as well for handling bad messages.

Related

message is not acknowledged but in rabbitmqManagement page it said the queue is empty (but I sent the message)?

When I try to click getMessages button in RabbitMQManagement I get a response which says it is empty, as in the picture belove.
However, I send 4 messages which are unacked because I make the acknowledgment manually.
If the callback function in my consumer does not/cannot add the message in the database it does not acknowledges the message.
So the queue has persistent=true but here I see that the queue is empty.
How can I prevent this? How can I have the message in the queue until i aknowledge it?
The message is "still in the queue", just not available for consumption.
Rabbitmq knows the messages have been given to consumer, and is waiting for the ack to delete them.
If you reject, you have the option to requeue the message (where it will given for consumption again if a consumer is availavble), or not.
I'd typically recommend configuring a dead letter exchange and reject the message without requeue as a more sturdy solution (you'd have configured a queue bound to the defined dead letter exchange).
In such case the rejected message would be published to the dead letter exchange and finish in the dead letter queue (the queue bound to the dead letter exchange) where you can consume them for review or other secondary processing.

I want to re-queue into RabbitMQ when there is error with added values to queue payload

I have a peculiar type of problem statement to be solved.
Configured RabbitMQ as message broker and its working but when there is failure in process in consume I'm now acknowledging with nack but it blindly re-queues with whatever already came in as payload but i want to add some-more fields to it and re-queue with simpler steps
For Example:
When consume gets payload data from RabbitMQ it will then process it and try to do some process based on it in multiple host machines, but due to some thing if one machine not reachable i need to process that alone after some time .
Hence I'm planning to re-queue failed data with one more fields with machine name again back to queue so it will be processed again with existing logic itself.
How to achieve this ? Can someone help on me
When a message is requeued, the message will be placed to its original position in its queue, if possible. If not (due to concurrent deliveries and acknowledgements from other consumers when multiple consumers share a queue), the message will be requeued to a position closer to queue head. This way you will end up in an infinite loop(consuming and requeuing the message). To avoid this, you can, positively acknowledge the message and publish it to the queue with the updated fields. Publishing the message puts it at the end of the queue, hence you will be able to process it after some time.
Reference https://www.rabbitmq.com/nack.html

RabbitMQ NACK messages

My experience: in a publish/subscribe scenario, if a subscriber nacks a message, the nacked message is immediately re-queued at the front of the queue and it will be the next message the subscriber gets.
Is there a way to avoid this? Is is possible to nack a message in a way that the next message will definetly not be the one just nacked?
I am using Node.js and amqp.node to communicate with RabbitMQ
Nack is a RabbitMQ-specific enhancement to the AMQP protocol. It allows a consumer of a message to notify the server when a message was not successfully processed. I assume you got this far already.
The interesting thing here is that AMQP did not originally consider Nack to be necessary. Why? Because the AMQP behavior when a consumer is unable to process a message is for the consumer to close the connection without ack-ing the message. Under this situation, the message is automatically requeued in the order it was originally in, and delivered to the next available consumer with the redelivered flag set.
Why would this be?
Because a Nack indicates an issue with the consumer, not the message. If the message itself is bad, AMQP assumed that the consumer would be smart enough to recognize this, ack the message, then take whatever other steps the programmer designed to deal with bad messages.
RabbitMQ added the Nack function which takes a requeue parameter. By default, requeue is true - meaning upon the nack, the broker will requeue the message. This is in keeping with the original intent of the AMQP design. However, if you pass requeue as false, the broker will dead-letter the message. This is a shortcut to the behavior that would normally have been designed in by a smart application architect using AMQP, so you can think of this as a convenience to the programmer.
Difference Between The Two
In the first case, the Nack indcates a problem with the message consumer. The consumer should take itself offline while it works out its issues. In the second case, the Nack indicates a problem with the message. The first case is a transient issue, while the second is a permanent failure.
What if I can't process a particular message right now but maybe later?
If your messaging structure was designed properly, this would never be true. If one particular message requires different processing paths or resources than another message, that message type should have its own queue. Consumers of that queue can stop consuming when a dependency for processing those messages is offline or unavailable.
Question: My experience: in a publish/subscribe scenario, if a subscriber nacks a message, the nacked message is immediately re-queued at the front of the queue and it will be the next message the subscriber gets.
Yes that is correct. When a message is requeued with
channel.basicNack, it will be placed to its original position in its
queue, if possible. If not (due to concurrent deliveries and
acknowledgements from other consumers when multiple consumers share a
queue), the message will be requeued to a position closer to queue
head. Source: https://www.rabbitmq.com/nack.html
Question: Is there a way to avoid this? Is is possible to nack a message in a way that the next message will definetly not be the one just nacked?
It is not possible to achieve this with nack. One way to achieve this is by re-publish the message back to queue where ever nack needed.
Get the message and immediately send the ack back.
Process the message, if successful do nothing.
If fails do not send the nack instead republish message back to the
queue.
As a general rule, you can consider that if your consumer runs normally, you should always ack a message, whatever the result of handling the message (both for errors or success).
You can reject/nack a bad formatted message with requeue = false to route it to a dead letter exchange and have actions on it (bind a queue and consume for e.g. post mortem analysis), or choose to ack it and do whatever is necessary (e.g. send other messages like BadRequest messages, ...).
The best way to (almost) never have problem is to ack as the last action of handling the message, and be prepared to handle redeliveries (idempotency may help). You can ack immediately upon delivery, but if the consumer crashes, the message is lost (and you'll need to handle that case by yourself – there are many patterns for that).
Hope this helps.

Resubmitting Expired Dead Letter Message back to Queue

I have huge number of messages in azure service bus dead letter queue. When I see the messages, I see that most of the messages are expired.
I want to know what happens when we try to re-submit the expired deadletter queue message back to its original queue?
Can anyone help me out in explaining this ?
Thank you !
I am trying to answer two of your questions below,
when you receive an expired message from the dead letter queue to process/resubmit to main queue(Using ReceiveAsync() to receive a message), the state of the message will be changed to deferred state. So, the message won't be available for receiving in the Dead-Letter queue anymore.
For your question on, what happens to the message when you resubmit, it would be submitted as a new message into the target queue.
We could use FormatDeadLetterPath() method to build the format name for the specified dead letter queue path and create a receiver and retrieve messages from a DLQ. If you’d like to resubmit message back into the main queue, you could create and send a new message based on retrieved message in DLQ. And you could investigate why the message has been dead-lettered via checking DeadLetterReason and DeadLetterErrorDescription properties.
This link explained Dead-Letter Queues with a sample, please refer to it.

How to put a message at the end of MQRabbit Queue

I'm working on a worker which is able to treat message from a RabbitMQ.
However, I am unsure of how to accomplish this.
If I receive a message and during my treating an error occurs, how can I put the message into the end of the queue?
I'm trying to using nack or reject, but the message is always re-put in the first position, and other messages stay frozen!
I don't understand why the message has to be put in the first position, I'm trying to "play" with other options like requeue or AllupTo but none of them seem to work.
Thank you in advance!
Documentation says:
Messages can be returned to the queue using AMQP methods that feature a requeue parameter (basic.recover, basic.reject and
basic.nack), or due to a channel closing while holding unacknowledged
messages. Any of these scenarios caused messages to be requeued at the
back of the queue for RabbitMQ releases earlier than 2.7.0. From
RabbitMQ release 2.7.0, messages are always held in the queue in
publication order, even in the presence of requeueing or channel
closure.
With release 2.7.0 and later it is still possible for individual
consumers to observe messages out of order if the queue has multiple
subscribers. This is due to the actions of other subscribers who may
requeue messages. From the perspective of the queue the messages are
always held in the publication order.
Remember to ack your successful messages, otherwise they will not be removed from the queue.
If you need more control over your rejected messages you should take a look to dead letter exchanges.
nack or reject either discard the message or re-queue the message.
For your requirement following could be suitable,
Once the consumer receives the message, just before start processing it, send ack() back to rabbitmq server.
Process the message then after, If found any error in the process then send ( publish ) the same message into the same queue. This will put the message at the back of the queue.
On successful processing do nothing. ack() has been already sent to rabbitmq server. Just take the next message and process it.

Resources