Messages fail, back off, retry, and land safely in a DLQ.
When asynchronous background tasks fail, a naive consumer crashes in an infinite loop, blocking all downstream traffic. An event-driven DLQ architecture retries with exponential backoff and isolates poison pills without message loss.
LIVE · Max 3 Retries · Exponential Backoff & DLQ
Processed: 0In DLQ: 0
Main Queue (3)tasks.inbox
MSG-001
Generate monthly invoice PDF
MSG-002
[POISON_PILL] Malformed JSON metadata
MSG-003
Send welcome onboarding email
Retry Queue (0)tasks.retry
No active retries
Dead Letter Queue (0)tasks.dlq
Zero dead letters (Healthy)
Completed (0)ACK / 200
None processed yet
On the live site, messages are routed through real Spring Boot event channels with exponential backoff and replay capabilities.
Dead Letter Queue Lifecycle
Main Queue → Consumer attempts processing → on failure, moves to Retry Queue with backoff (2s, 4s, 8s) → after 3 attempts, moves to Dead Letter Queue (DLQ).
Producer
API / Webhook
Publish event
Main Queue
tasks.inbox
Consume task
Retry Queue
Exponential backoff
Attempt 1 & 2 fail
Worker Consumer
Async processor
Attempt 3 fails (DLQ)
Dead Letter Queue
tasks.dlq (Safe park)
Poison Pill: 3 retries with backoff → safely parked in DLQ | Zero head-of-line blocking for healthy messages
Spring Kafka / Consumer DLQ Handler
@Bean
public DefaultErrorHandler errorHandler(KafkaTemplate<String, Object> template) {
// Exponential backoff: 1s initial, 2.0x multiplier, max 3 attempts
ExponentialBackOff backOff = new ExponentialBackOff(1000L, 2.0);
backOff.setMaxAttempts(3);
DeadLetterPublishingRecoverer recoverer = new DeadLetterPublishingRecoverer(template,
(record, ex) -> new TopicPartition("tasks.dlq", record.partition())
);
return new DefaultErrorHandler(recoverer, backOff);
}
Retrying in memory with Thread.sleep blocks the Kafka consumer partition, preventing other messages from advancing. Publishing failed records to dedicated retry topics maintains pipeline throughput.
At-Least-Once Delivery vs At-Most-Once
At-least-once with idempotent consumer processing ensures zero data loss during broker rebalances or node failures, whereas at-most-once drops messages whenever consumers restart.
Manual DLQ Redrive vs Automatic Reprocessing
Poison pills caused by schema drift or bugs require code fixes before redriving. Manual, audited replay tools ensure fixed messages do not fail a second time.