Ack & Reject
Selectively acknowledge or reject messages based on content
Overview
Ack and reject give you per-message control over queue delivery instead of an all-or-nothing batch outcome. When receiveQueuesMessages fetches a batch with autoAck = false, 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 QueueReceivedMessage: ack(), which permanently removes it from the queue, and reject(), which returns it to the queue for redelivery. 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 reject() on each one individually.
Prerequisites
- KubeMQ server running on
localhost:50000 - Kotlin SDK installed (
implementation("io.kubemq.sdk:kubemq-sdk-kotlin:1.0.1"))
Code
package io.kubemq.sdk.examples.queues
import io.kubemq.sdk.client.KubeMQClient
import io.kubemq.sdk.queues.queueMessage
import kotlinx.coroutines.runBlocking
private const val ADDRESS = "localhost:50000"
private const val CLIENT_ID = "kotlin-queues-ack-reject"
private const val CHANNEL = "kotlin-queues.ack-reject"
fun main() = runBlocking {
val client = KubeMQClient.queues {
address = ADDRESS
clientId = CLIENT_ID
}
client.use {
// Send multiple messages
val bodies = listOf("important-task", "bad-task", "another-good-task")
bodies.forEach { body ->
client.sendQueuesMessage(queueMessage {
channel = CHANNEL
this.body = body.toByteArray()
})
println("Sent: $body")
}
// Receive and selectively ack/reject
val response = client.receiveQueuesMessages {
channel = CHANNEL
maxItems = 10
waitTimeoutMs = 5000
autoAck = false
}
for (msg in response.messages) {
val body = String(msg.body)
if (body.contains("bad")) {
msg.reject()
println("Rejected: $body")
} else {
msg.ack()
println("Acked: $body")
}
}
// Cleanup rejected messages
val cleanup = client.receiveQueuesMessages {
channel = CHANNEL
maxItems = 10
waitTimeoutMs = 1000
autoAck = true
}
println("Cleanup: consumed ${cleanup.messages.size} rejected messages.")
println("Done.")
}
}How It Works
- Each
QueueReceivedMessageprovidesack()andreject()methods for individual message handling. - Rejected messages are returned to the queue for redelivery to another consumer.
- This pattern is useful for content-based filtering or validation before processing.
Related
Was this page helpful?