KubeMQ
Client SDKsNode.jsHow-to guidesQueues

Ack & Reject

Selectively acknowledge or reject individual KubeMQ queue messages in Node.js to confirm successes and discard failed deliveries.

Overview

Ack and reject give you per-message control over queue delivery instead of an all-or-nothing batch outcome. When receiveQueueMessages() fetches a batch, each message stays locked on the broker — invisible to other consumers — until the consumer explicitly settles it. That's what you need when one bad record in a batch shouldn't take the rest down with it.

Settlement happens through two calls on the received message: msg.ack(), which permanently removes it from the queue, and msg.nack(), which returns it to the queue for redelivery (or routes it to the dead-letter queue if maxReceiveQueue is configured). Internally the broker tracks this against a receive count, which a dead-letter policy can use to stop retrying a poison message forever.

Gotchas: an unsettled message isn't gone — it snaps back to the queue once the visibility timeout expires, so a slow consumer looks identical to a rejecting one; settle every message before that deadline, and never assume a batch is fully processed until you've called ack() or nack() on each one individually.

Prerequisites

  • KubeMQ server running on localhost:50000
  • Node.js SDK installed (npm install kubemq-js)

Code

ack-reject.ts
/**
 * Example: Message Acknowledgment and Rejection
 *
 * Demonstrates the two message handling options after receiving a queue
 * message via simple receive: acknowledge (success) or reject (send to
 * dead-letter queue).
 *
 * Prerequisites:
 *   - KubeMQ server running on localhost:50000
 *
 * Run: npx tsx examples/queues/ack-reject.ts
 */
import { KubeMQClient, createQueueMessage } from 'kubemq-js';

async function main(): Promise<void> {
  const client = await KubeMQClient.create({
    address: 'localhost:50000',
    clientId: 'js-queues-ack-reject-client',
  });

  try {
    // Send test messages with different intents.
    for (const task of ['valid-task', 'bad-format', 'another-valid-task']) {
      await client.sendQueueMessage(
        createQueueMessage({
          channel: 'js-queues.ack-reject',
          body: task,
          tags: { type: task },
        }),
      );
    }

    const messages = await client.receiveQueueMessages({
      channel: 'js-queues.ack-reject',
      waitTimeoutSeconds: 5,
      maxMessages: 10,
    });

    for (const msg of messages) {
      const body = new TextDecoder().decode(msg.body);

      if (body === 'bad-format') {
        // Permanently reject — message goes to dead-letter queue if configured.
        await msg.nack();
        console.log('Rejected:', body);
      } else {
        // Acknowledge successful processing.
        await msg.ack();
        console.log('Acknowledged:', body);
      }
    }
  } finally {
    await client.close();
  }
}

main().catch(console.error);

How It Works

  • receiveQueueMessages() with maxMessages: 10 fetches up to 10 messages in a single poll and locks them for processing.
  • await msg.ack() marks the message as successfully processed — it is permanently removed from the queue.
  • await msg.nack() permanently rejects the message: if maxReceiveQueue is configured on the message policy the message moves to the dead-letter queue; otherwise it is discarded.
  • Each ack/nack must be called before the visibility timeout expires; the waitTimeoutSeconds on the receive controls how long the server waits for a consumer, not the ack deadline.

Was this page helpful?

On this page