nats message queue – ack a message from jetstream consumer in a separate request – Node.js

by
Ali Hasan
nats.io node.js

Quick Fix: – When using direct get, message acknowledgment does not apply as the progress of consumed messages is not tracked by the stream.

The Problem:

In NATS, a consumer can receive and acknowledge messages in a single request. However, I want to build an API where I need to handle message acknowledgement in a separate request. Specifically, I have a GET endpoint for retrieving messages and a POST endpoint for acknowledging them. However, when I try to acknowledge a message in the POST endpoint after receiving it in the GET endpoint, the message object doesn’t have an ‘ack’ method anymore. How can I manually acknowledge a message sequence in a separate request?

The Solutions:

\n

Solution 1: Leverage Consumer handles for acknowledgement

\n

Instead of using streams.get() to retrieve a message directly from a stream, utilize a consumer handle to receive messages. This consumer handle will enable you to acknowledge messages explicitly, even after the initial context of the message is lost. Here’s the approach:

  1. Create a JetStream Consumer:

    const consumer = await jetstream.consumers.create({
         stream: 'mystream',
         name: 'myconsumer'
     });
    
  2. Pull Messages from the Stream:
    Use the consume() method to start pulling messages from the stream:

    const messages = await consumer.consume({ max_messages: maxMessages });
    
  3. Process and Acknowledge Messages:
    Process the messages as required, and acknowledge them individually:

    for await (const m of messages) {
         // Some processing logic
         await m.ack();
     }
    
  4. Handle Acknowledgments Separately:
    Create a separate API endpoint to handle acknowledgment requests. When a message acknowledgment request is received, use the consumer handle to acknowledge the specified sequence ID:

    // Inside the implementation of POST /events/ack endpoint
    const s = await jetstream.streams.get('mystream');
    await s.ack(lastReceivedEventSeqId);
    

By using a consumer handle, you can acknowledge messages explicitly, even if the context of the original message is lost, ensuring reliable message processing and acknowledgment.

.

Q&A

Reliability of ack against lost messages

ack does not improve reliability in case of temporary network problems. Once ack is performed, the server considers the message fully processed

Manually acknowledgement of messages

There is no built-in feature on the server side to manually ack messages

Automatic ack on lost messages

The only way to ack messages that were delivered but not acked is to resend them