Rabbit listener prefetch controls how many messages a consumer can hold without acknowledgment, not how many it has committed.
Spring AMQP prefetch: bound unacknowledged messages before raising concurrency
Count in-flight bytes
A parcel-photo event can carry 420 KiB of metadata and thumbnails. With prefetch 250, one consumer may hold roughly 103 MiB of payload before object overhead; four concurrent consumers can multiply that pressure. Lower prefetch when messages are large, handlers are slow or strict ordering matters. An executor limit does not remove messages already delivered to listener containers.
Tie acknowledgement to the effect
A listener may commit a database change and lose its connection before the broker records the acknowledgment. The event can be redelivered, even with a low prefetch. Keep the dedup key and business write in one database transaction. Prefetch is capacity control, not exactly-once processing.
Measure under a stalled handler
Run two consumers, block one handler, publish 47 messages, and measure unacknowledged count, heap use and distribution. Lower prefetch until memory and fairness meet the service budget. The property sketch assumes a simple listener container; a direct container or per-listener factory needs its own configuration check.
Implementation sketch
spring:
rabbitmq:
listener:
simple:
prefetch: 23
concurrency: 2
max-concurrency: 4Cost and verification
Smaller prefetch limits memory and can improve fairness, but adds broker round trips and may lower throughput. Measure with production-sized messages.
Common Mistakes
- Do not equate prefetch with completed transactions.
- Do not raise concurrency without accounting for prefetch times message size.
- Do not assume prefetch one prevents redelivery after a lost acknowledgment.
Read next
Spring AMQP poison messages: reject, requeue and dead-letter are different decisions, Spring consumer deduplication: commit the event ID with the mutation, Spring Kafka manual acknowledgement: commit work before advancing the offset, Spring task executors: reject work when every slot is occupied.
