Skip to content

Prefetch & QoS

Put two consumers on a queue and RabbitMQ hands out messages round-robin — one to each, in turn. That sounds fair, but it’s fair by count, not by work. If it blindly pushes messages as fast as it can, a consumer that grabbed ten slow messages is buried while another sits idle. Worse, with manual ack and no limit, the broker can shove hundreds of unacked messages at one consumer, blowing up its memory.

The fix is prefetch, set via basic.qos.

Prefetch caps how many unacknowledged messages a consumer may hold at once. Set it to 1 and RabbitMQ won’t give a consumer a second message until it acks the first. Set it to 50 and a consumer can have up to 50 in flight.

This turns round-robin into fair dispatch: a busy consumer stops receiving new work until it catches up, so messages naturally flow to whoever is actually free.

flowchart TB
  subgraph rr["No prefetch limit — round-robin by count"]
    q1["queue"] --> w1["worker A (busy,
buried in slow tasks)"]
    q1 --> w2["worker B (idle,
nothing queued to it)"]
  end
  subgraph fd["prefetch = 1 — fair dispatch"]
    q2["queue"] --> w3["worker A
(1 at a time)"]
    q2 --> w4["worker B
(gets the next free one)"]
  end
Round-robin (no limit) versus fair dispatch (prefetch)

There’s a trade-off:

  • prefetch = 1 — the fairest, and the safest for long or uneven tasks. The cost is a little latency: a consumer waits for the ack round-trip before getting the next message. Great for slow jobs (image processing, emails).
  • Higher prefetch (e.g. 10–100) — more throughput for fast, uniform tasks, because the consumer always has a buffer ready and isn’t stalled waiting for the next delivery. The cost is less even distribution and more memory per consumer.

A good default for typical background jobs is a small number (1 for slow tasks, 10–50 for fast ones), tuned by watching queue depth and consumer utilisation. Never leave it unbounded in production.

// at most 1 unacked message per consumer at a time
await channel.prefetch(1);
channel.consume('orders', handler, { noAck: false });
By default, how does RabbitMQ distribute messages across multiple consumers on one queue?
What does prefetch (basic.qos) limit?
Why can an unbounded prefetch be dangerous with manual ack?
For slow, uneven tasks, what prefetch value gives the fairest distribution?