Consumer Concurrency
Separate RabbitMQ prefetch from handler concurrency for better control over throughput and service pressure.
Rabbit Relay separates RabbitMQ prefetch from handler concurrency.
This gives you better control over throughput and service pressure.
Prefetch vs concurrency
await sub.consume({
prefetch: 50,
concurrency: 10,
});This means:
- RabbitMQ can deliver up to 50 unacknowledged messages
- Rabbit Relay runs at most 10 handlers in parallel
- Remaining delivered messages wait in memory until a handler finishes
Why this matters
Without a concurrency limit, a consumer can overload:
- database pools
- downstream APIs
- CPU-heavy workers
- memory
- third-party services
prefetch controls RabbitMQ delivery pressure.
concurrency controls application execution pressure.
Defaults
If concurrency is not set, it defaults to prefetch.
await sub.consume({
prefetch: 20,
});This allows up to 20 concurrent handlers.
If neither is set, both default to 1.
Recommended settings
For I/O-heavy handlers:
await sub.consume({
prefetch: 50,
concurrency: 10,
});For CPU-heavy handlers:
await sub.consume({
prefetch: 5,
concurrency: 2,
});For strict sequential processing:
await sub.consume({
prefetch: 1,
concurrency: 1,
});Warning: concurrency greater than prefetch
If concurrency is greater than prefetch, RabbitMQ still cannot deliver more than prefetch unacknowledged messages.
await sub.consume({
prefetch: 5,
concurrency: 20,
});Rabbit Relay will warn because practical concurrency is limited by prefetch.
Summary
prefetchcontrols unacknowledged messages from RabbitMQconcurrencycontrols parallel handler execution- Use both together for predictable throughput
- Keep handlers idempotent because delivery is still at-least-once