The poison message problem
One message that can never succeed will saturate a consumer forever unless you count attempts.
Open this lesson in the learning hubKey points
- Rejecting with requeue true puts a bad message straight back - that is a hot redelivery loop.
- The redelivered flag only says it was delivered before; it is a boolean, not a counter.
- Quorum queues count attempts with
x-delivery-limit, which defaults to 20 in RabbitMQ 4.0. - Classic queues have no delivery counter, so count in a header or read the x-death count yourself.
- A parking lot queue holds what will never succeed and should page a human rather than retry forever.
- Spring AMQP listener retry is off by default; enable it and add a RepublishMessageRecoverer.
Example
@Bean
RetryOperationsInterceptor retryInterceptor() {
return RetryInterceptorBuilder.stateless()
.maxAttempts(4) // 1 try + 3 retries
.backOffOptions(1_000, 2.0, 20_000) // 1s, 2s, 4s ... cap 20s
.recoverer(new RepublishMessageRecoverer(
rabbitTemplate, "orders.dlx", "parking-lot"))
.build();
}
// and refuse to requeue by default, or every failure loops:
factory.setDefaultRequeueRejected(false);
Bound the attempts somewhere - x-delivery-limit, an x-death count or a header - or one message runs forever.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the RabbitMQ Course course, and every lesson in it is listed on the RabbitMQ Course contents page.