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



## 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. Range acknowledgment lets you settle any subset you choose — for example, just the first N messages, or only the ones your handler actually confirmed — in one call.

`response.ack_range(sequence_range: sequences)` takes an array of broker-assigned sequence numbers — read from each message in the poll response — and acknowledges all of them together. Any sequence you leave out of the array is left unsettled and returns to the queue for redelivery once the visibility window expires.

**Gotchas:** the sequences you pass must be numbers your handler actually received in that poll — passing a stale or unknown sequence isn't a safe no-op you can rely on. Messages you never include in any `ack_range` call aren't implicitly skipped forever; they come back for redelivery once the timeout elapses, so a handler that forgets to settle a message isn't "done," it's "will retry." And selective settlement only works when the poll isn't using auto-ack — with auto-ack on, the broker settles the whole batch the moment it's delivered.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Ruby SDK installed (`gem install kubemq`)

## Code [#code]

```ruby title="main.rb"
require 'kubemq'

address = ENV.fetch('KUBEMQ_ADDRESS', 'localhost:50000')
channel = 'ruby-queues.ack-range'

begin
  client = KubeMQ::QueuesClient.new(address: address, client_id: 'qstream-ackrange-example')
  puts "Connected to #{address}"

  5.times do |i|
    msg = KubeMQ::Queues::QueueMessage.new(channel: channel, metadata: "item-#{i}", body: "data-#{i}")
    client.send_queue_message(msg)
  end
  puts 'Pre-sent 5 messages'

  receiver = client.create_downstream_receiver
  request = KubeMQ::Queues::QueuePollRequest.new(channel: channel, max_items: 5, wait_timeout: 5)
  response = receiver.poll(request)

  if response.error?
    puts "Poll error: #{response.error}"
  else
    puts "Polled #{response.messages.size} messages"
    sequences = response.messages.first(3).filter_map { |m| m.attributes&.sequence }
    puts "Acking range: #{sequences.inspect}"
    response.ack_range(sequence_range: sequences)
    puts 'Ack range complete'
  end
rescue KubeMQ::Error => e
  puts "KubeMQ error: #{e.message}"
ensure
  receiver&.close
  client&.close
  puts 'Done'
end
```

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

* `ack_range` acknowledges specific messages by their broker-assigned sequence numbers.
* This allows selective acknowledgement within a batch — ack some, leave others for reprocessing.
* Review timeouts, channel names, and client IDs before running against shared environments.

## Related [#related]

* [Pattern overview](/learn/queues/getting-started)
* [Ruby SDK Reference](/sdks/ruby/reference)
* [Ack All](/sdks/ruby/how-to/queues/ack-all)
* [Ack/Reject](/sdks/ruby/how-to/queues/ack-reject)
