Ack Range
Selectively acknowledge specific messages from a polled batch by sequence with the Java SDK.
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.
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
- 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)
Code
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
pollMaxMessages(5)fetches up to 5 messages in one call with manual ack, so eachQueueMessageReceivedmust be settled explicitly viaack()orreject().- 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 ifmaxReceiveCountis 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
Was this page helpful?