KubeMQ
ConnectorsRabbitMQ (AMQP 0-9-1)How-to guides

Queues and Consumers

Declaring queues, consuming, acknowledging, prefetch (QoS), and basic.get on the KubeMQ RabbitMQ connector — every AMQP queue maps to a KubeMQ Queue channel.

Every AMQP queue maps to a KubeMQ Queue channel amqp.{vhost}.{queue}. This guide covers declaring queues, consuming, acknowledging (ack / nack / reject), prefetch (QoS), and basic.get.

Consumption is at-least-once: unacked deliveries are requeued on disconnect, so there is zero loss even on an ungraceful disconnect. Exactly-once is NOT provided — plan for redelivery (Redelivered == true). See Reliability.

Declaring queues

queue.declare supports durable / exclusive / auto-delete / arguments.

AspectBehavior
IdempotencyIdentical args → ok; mismatch → 406 precondition-failed.
Passive declarepassive=true: exists → ok; missing → 404 not-found.
Server-named queuesqueue.declare("") → the server mints amq.gen-{uuid22}.
Exclusive queuesConnection-scoped. Cross-connection access (including passive declare) → 405 resource-locked. Auto-deleted when the owning connection closes. Node-local in a cluster.
Auto-delete queuesDeleted when the last (cluster-aware) consumer cancels.

Exclusive queues are node-local. In a cluster, an exclusive queue lives only on the node that owns the connection; cross-node access fails. For single-node deployments this is invisible. See Reliability and Migration from RabbitMQ.

Consuming

basic.consume registers a consumer (an auto-generated ctag-{n} if the tag is empty). The server then delivers basic.deliver + content header + body.

TriggerResult
Duplicate consumer tag on a channel530 not-allowed (connection error, RabbitMQ dialect)
Exclusive consumer over existing consumers403 access-refused

A minimal consume loop:

// amqp091-go — consume and manually ack each delivery.
deliveries, _ := ch.Consume("orders", "", false /* autoAck */, false, false, false, nil)
for d := range deliveries {
    process(d.Body)
    _ = d.Ack(false) // multiple=false
}
# pika — consume with manual ack.
def on_message(ch, method, props, body):
    process(body)
    ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(queue="orders", on_message_callback=on_message, auto_ack=False)
channel.start_consuming()
// amqp-client — consume with manual ack.
DeliverCallback cb = (tag, delivery) -> {
    process(delivery.getBody());
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
};
channel.basicConsume("orders", false /* autoAck */, cb, t -> {});
// amqplib — consume with manual ack.
await channel.consume("orders", (msg) => {
  if (!msg) return;
  process(msg.content);
  channel.ack(msg);
}, { noAck: false });
// RabbitMQ.Client — consume with manual ack.
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (_, ea) =>
{
    Process(ea.Body.ToArray());
    channel.BasicAck(ea.DeliveryTag, multiple: false);
};
channel.BasicConsume("orders", autoAck: false, consumer);
# bunny — consume with manual ack.
queue.subscribe(manual_ack: true, block: true) do |delivery_info, _props, body|
  process(body)
  channel.ack(delivery_info.delivery_tag)
end
// lapin — consume with manual ack.
let mut consumer = channel.basic_consume(
    "orders", "", BasicConsumeOptions::default(), FieldTable::default()).await?;
while let Some(delivery) = consumer.next().await {
    let delivery = delivery?;
    process(&delivery.data);
    delivery.ack(BasicAckOptions::default()).await?;
}

Ack / nack / reject

MethodEffect
basic.ack(tag, multiple)AckRange — message(s) consumed.
basic.nack / basic.reject(tag, requeue=true)NAckRange — requeued at the tail.
basic.reject / basic.nack(tag, requeue=false)Dropped, or dead-lettered if a DLX is configured.
Unknown delivery tag406 precondition-failed.

Requeue lands at the tail. Requeued messages re-enter at the queue tail, not the head (a deviation from RabbitMQ classic head-requeue). Fairness ordering therefore differs.

At-least-once consumption

Unacked deliveries are requeued on disconnect (a downstream nack-all safety net), so there is zero loss even on an ungraceful disconnect. Exactly-once is NOT provided — plan for redelivery (Redelivered == true).

Prefetch (QoS)

basic.qos(prefetch-size, prefetch-count, global) limits in-flight unacked deliveries.

ScopeglobalMeaning
Per-consumerfalse (RabbitMQ default)The budget applies to each consumer.
Per-channeltrueThe budget is shared across all consumers on the channel.
  • prefetch-size is accepted but inert.
  • Default = unlimited.
  • Effective allowance = min(per-consumer budget, remaining channel-global budget).

basic.get (pull)

basic.get returns get-ok (with a delivery tag) or get-empty.

basic.get has a ~1s latency floor. On an empty queue, basic.get blocks up to ~1 second (the KubeMQ minimum wait timeout) before returning get-empty. Polling with basic.get is therefore slow — prefer basic.consume for throughput. GetBatchSize (default 32) bounds per-Get pulls.

Recover / flow

MethodBehavior
basic.recover(requeue=true)Nack-all unacked on the channel (tail requeue).
basic.recover(requeue=false) / basic.recover-async540 not-implemented.
channel.flowReplies flow-ok, takes no action (deprecated in the AMQP spec).

Purge / delete

  • queue.purge returns the exact message count purged.
  • queue.delete sends a server-initiated basic.cancel(consumerTag) to live consumers and returns the residual count.

Was this page helpful?

On this page