# Ack Range (/sdks/java/how-to/queues/ack-range)



<Callout type="info" title="Which to use">
  This page is about **selective/per-message** settlement of a polled batch — acking or rejecting individual messages by sequence while leaving the rest pending. For settling an **entire polled batch** in one call, see [Ack All](./ack-all).
</Callout>

## Overview [#overview]

A single poll response often bundles several messages into one batch, but "successfully processed" rarely applies to all of them uniformly — one handler might fail while its siblings succeed. Settling the whole batch together forces an all-or-nothing outcome: either you redeliver work you already finished, or you silently drop work you didn't. Per-message settlement lets each message's outcome reflect what actually happened to it, instead of the worst result in the batch.

Each `QueueMessageReceived` returned by `receiveQueueMessages` carries its own broker-assigned `getSequence()`. Calling `msg.ack()` on one message settles only that message; calling `msg.reject()` on another explicitly returns it to the queue for redelivery. Messages you don't touch at all are left pending — still redeliverable — until their own `ack()`/`reject()` is called or the visibility timeout expires.

**Gotchas:** messages you never touch aren't automatically fine — once the visibility timeout elapses, anything left unsettled goes back to the queue, so a handler that forgets to settle a message isn't "done," it's "will retry." Every `reject()` increments that message's `getReceiveCount()`, which can trigger dead-letter routing if `maxReceiveCount` is configured — so a bug that rejects indiscriminately can drain a message's retry budget fast. And selective settlement only works with messages fetched with `autoAck` disabled — with auto-ack on, the broker settles the entire batch the moment it's delivered, before your code runs.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Java SDK installed (`implementation 'io.kubemq.sdk:kubemq-sdk-Java:3.1.1'` (Gradle) or Maven dependency from [Getting Started](/sdks/java))

## Code [#code]

```java title="AckRangeExample.java"
package io.kubemq.example.queuesstream;

import io.kubemq.sdk.queues.*;
import java.util.UUID;

/**
 * AckRangeExample for Queues Stream
 *
 * Demonstrates selectively acknowledging specific messages using individual
 * message ack()/reject() calls. This allows fine-grained control over which
 * messages in a batch are acknowledged.
 */
public class AckRangeExample {
    private static final String ADDRESS = "localhost:50000";
    private static final String CLIENT_ID = "java-queues-ack-range-client";
    private static final String CHANNEL = "java-queues.ack-range";

    public static void main(String[] args) {
        // Create a client connected to the KubeMQ server
        try (QueuesClient client = QueuesClient.builder().address(ADDRESS).clientId(CLIENT_ID).build()) {
            // Create the queue channel
            client.createQueuesChannel(CHANNEL);

            // Send messages to the queue
            for (int i = 1; i <= 5; i++) {
                client.sendQueueMessage(QueueMessage.builder()
                        .channel(CHANNEL).body(("Range msg " + i).getBytes()).build());
            }

            // Poll for a batch of messages with manual ack
            QueuesPollResponse response = client.receiveQueueMessages(QueuesPollRequest.builder()
                    .channel(CHANNEL).pollMaxMessages(5).pollWaitTimeoutInSeconds(5).build());

            System.out.println("Received " + response.getMessages().size() + " messages.");

            // Selectively settle by sequence: ack even sequences, reject odd ones
            for (QueueMessageReceived msg : response.getMessages()) {
                long sequence = msg.getSequence();
                if (sequence % 2 == 0) {
                    msg.ack();
                    System.out.println("  Acked: seq=" + sequence);
                } else {
                    msg.reject();
                    System.out.println("  Rejected: seq=" + sequence);
                }
            }

            // Clean up rejected messages (receive and auto-ack)
            QueuesPollResponse cleanup = client.receiveQueueMessages(QueuesPollRequest.builder()
                    .channel(CHANNEL).pollMaxMessages(10).pollWaitTimeoutInSeconds(1).autoAckMessages(true).build());
            System.out.println("\nRemaining messages cleaned up: " + cleanup.getMessages().size());

            // Clean up resources
            client.deleteQueuesChannel(CHANNEL);
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

```

## How It Works [#how-it-works]

* `pollMaxMessages(5)` fetches up to 5 messages in one call with manual ack, so each `QueueMessageReceived` must be settled explicitly via `ack()` or `reject()`.
* Settlement decisions are made per-message using the broker-assigned `msg.getSequence()` (even = ack, odd = reject in this example).
* Rejected messages are returned to the queue for redelivery; their `getReceiveCount()` increments, which can trigger dead-letter routing if `maxReceiveCount` is set.
* This per-message settlement pattern is the foundation for selective processing: only confirmed-successful messages are removed from the queue, while the rest remain redeliverable.

## Related [#related]

* [Pattern overview](/learn/queues/getting-started)
* [Java SDK Reference](/sdks/java/reference/queues)
* [Send & Receive](/sdks/java/tutorials/send-receive)
* [Ack All](/sdks/java/how-to/queues/ack-all)
