Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set a custom header before nack-ing a message #735

Closed
dimisus opened this issue Jul 31, 2023 · 5 comments
Closed

Set a custom header before nack-ing a message #735

dimisus opened this issue Jul 31, 2023 · 5 comments

Comments

@dimisus
Copy link

dimisus commented Jul 31, 2023

If the above does not help, please provide as much of the following information as is relevant...

  • A clear and concise description of the problem
  • RabbitMQ version - 3.11.10
  • amqplib version - 0.9.1
  • Node.js version - 20+

I desperately want to set a header for a message that is going to be nack'ed. But apparently it is impossible to set a custom header on a message since nack only uses a reference to a message. Is there any work around or any possibility I am not able to find?

What I want to achieve is to set a hint of a reason why the message was nack'ed as a custom header. Which would make debugging and processing of nack'ed message in production much easier and one can react to issues faster.

If I go the hacky way and publish the messages directly to the DLX I may lose a lot of built-in functionality such as the x-death headers etc.

 class MessageBroker ... {

  ...

  nack(id: number | string, queueName: string, reason: string | null = null): void {

    // get the original message from local store
    const originalMessage = this.actives[id];

    // set a header to the message payload
    if (reason && typeof reason === 'string') {
      originalMessage.properties.headers = {
        ...originalMessage.properties.headers,
        'x-nack-reason': reason.substring(0, 63),
      };
    }

    // nack the message using the appropriate channel
    this.channels[queueName].nack(originalMessage, false, dlx);

    delete this.actives[id];
  }
@cressie176
Copy link
Collaborator

cressie176 commented Jul 31, 2023

Hi @dimisus,

Unfortunately there is no good way to do this with amqp or RabbitMQ amqplib. As you say, the only way is to republish the message.

Rascal (a wrapper for amqp) has the option of republishing the message back to the original queue after copying the headers and adding a failure reason. It also adds a special header instructing Rascal to immediately nack the message on redelivery rather than attempting to process it.

You could do something similar, but it still feels hacky and creates the potential for a duplicate message since the original message is not acknowledged/discarded before the mutated one is republished.

@dimisus
Copy link
Author

dimisus commented Aug 1, 2023

Hi. Thank you for the quick reply. Pity...

@dimisus dimisus closed this as completed Aug 1, 2023
@carlhoerberg
Copy link
Contributor

You can enable transaction on the channel, and then republish the message and ack the original message in a single transaction.

@dimisus
Copy link
Author

dimisus commented Aug 2, 2023

Beg you pardon, but not it is not obvious how to:

https://amqp-node.github.io/amqplib/channel_api.html

I am thinking about republishing the message using the delayed message plugin to force it for another full cycle.

@cressie176
Copy link
Collaborator

Unfortunately transactions aren't supported with amqplib. There's a discussion here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants