Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring AMQP poison messages: reject, requeue and dead-letter are different decisions

Last updated: 1 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

A listener failure can requeue forever unless the container and broker have an explicit retry and dead-letter policy.

Classify the failure

A temporary ledger database outage may merit a bounded retry. A malformed parcel event with a missing tenant ID will not become valid after a thousand deliveries. By default, a failed listener can be requeued, so the same message may form a hot loop. AmqpRejectAndDontRequeueException marks an individual failure as non-requeueable; a broker dead-letter exchange must exist if the team wants to retain that rejected message. Kafka poison handling has a different binder and offset model.

Keep the dead-letter path observable

Record message ID, schema revision, rejection reason and tenant without dumping credentials or payload secrets. A dead-letter queue needs capacity, retention and a human replay procedure. After a parser fix, replay through the normal consumer with the business dedup key intact. Blindly returning every dead-lettered message to the main queue can recreate the original loop.

Test the broker topology

Send one invalid event and one valid event. Assert the invalid event reaches the dead-letter queue once, the valid one commits, and the listener remains available. Then test a transient failure with the configured retry limit. This code marks one rejection; without a bound queue and dead-letter exchange, the broker may discard it.

Implementation sketch

Java
@RabbitListener(queues = "parcel-events")
public void applyParcel(ParcelEvent event) {
    if (event.tenantId() == null) {
        throw new AmqpRejectAndDontRequeueException("missing tenant identity");
    }
    parcelLedger.applyOnce(event);
}

Cost and verification

Dead-letter storage and bounded retries add broker traffic. Requeue loops consume CPU and can starve valid messages, so track redelivery count and queue age.

Common Mistakes

  • Do not assume rejecting without requeue automatically creates a dead-letter queue.
  • Do not retry permanent validation failures indefinitely.
  • Do not replay dead-letter records without a dedup and repair plan.

Read next

Spring AMQP prefetch: bound unacknowledged messages before raising concurrency, RabbitTemplate confirms and returns: broker acceptance is not consumer completion, Spring consumer deduplication: commit the event ID with the mutation, Spring outbox retry budget: park a poison event for inspection.

spring
spring-production
rabbit-reject-dead-letter
Storage details