Retry with Dead Letter in RabbitMQ: Setup and Example
To implement retry with dead letter in RabbitMQ, configure a queue with a
x-dead-letter-exchange and set message TTL for retry delay. When a message is rejected or expires, it moves to the dead letter exchange, which routes it back to the original queue for retry.Syntax
To set up retry with dead letter in RabbitMQ, you need to declare two queues and exchanges: the main queue and a dead letter queue. The main queue has these key arguments:
x-dead-letter-exchange: The exchange where rejected or expired messages are sent.x-message-ttl: Time in milliseconds before a message expires and is dead-lettered.x-dead-letter-routing-key: Optional routing key for dead letter messages.
The dead letter queue receives messages and can route them back to the main queue for retry.
python
channel.exchange_declare(exchange='dlx', exchange_type='direct') channel.queue_declare(queue='main_queue', arguments={ 'x-dead-letter-exchange': 'dlx', 'x-message-ttl': 5000, 'x-dead-letter-routing-key': 'retry' }) channel.queue_declare(queue='retry_queue', arguments={ 'x-dead-letter-exchange': '', 'x-dead-letter-routing-key': 'main_queue', 'x-message-ttl': 5000 }) channel.queue_bind(queue='retry_queue', exchange='dlx', routing_key='retry')
Example
This example shows how to declare a main queue with a dead letter exchange and a retry queue. Messages rejected from the main queue are sent to the dead letter exchange, which routes them to the retry queue. The retry queue has a TTL and dead letters messages back to the main queue, creating a retry loop.
python
import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # Declare dead letter exchange channel.exchange_declare(exchange='dlx', exchange_type='direct') # Declare main queue with dead letter exchange and routing key channel.queue_declare(queue='main_queue', arguments={ 'x-dead-letter-exchange': 'dlx', 'x-dead-letter-routing-key': 'retry' }) # Declare retry queue with TTL and dead letter back to main queue channel.queue_declare(queue='retry_queue', arguments={ 'x-message-ttl': 5000, # 5 seconds delay 'x-dead-letter-exchange': '', # default exchange 'x-dead-letter-routing-key': 'main_queue' }) # Bind retry queue to dead letter exchange channel.queue_bind(queue='retry_queue', exchange='dlx', routing_key='retry') # Publish a test message channel.basic_publish(exchange='', routing_key='main_queue', body='Test message') print('Message sent to main_queue') connection.close()
Output
Message sent to main_queue
Common Pitfalls
- Missing dead letter exchange: Not setting
x-dead-letter-exchangemeans messages won't be routed for retry. - No TTL on retry queue: Without
x-message-ttl, messages won't expire and retry won't happen. - Infinite retry loops: Without a max retry count or delay increase, messages can retry forever causing resource issues.
- Incorrect routing keys: Dead letter routing keys must match bindings or messages get lost.
python
## Wrong: No dead letter exchange channel.queue_declare(queue='main_queue') ## Right: With dead letter exchange channel.queue_declare(queue='main_queue', arguments={ 'x-dead-letter-exchange': 'dlx' })
Quick Reference
x-dead-letter-exchange: Exchange to send dead letter messages.x-message-ttl: Time before message expires for retry delay.x-dead-letter-routing-key: Routing key for dead letter messages.- Use a retry queue with TTL and dead letter back to main queue for retry.
- Consider adding retry count headers to limit retries.
Key Takeaways
Set
x-dead-letter-exchange on your main queue to route failed messages for retry.Use
x-message-ttl on the retry queue to delay retries before reprocessing.Bind the retry queue to the dead letter exchange with the correct routing key.
Implement retry limits to avoid infinite retry loops and resource exhaustion.
Dead letter exchanges enable clean separation of failed message handling and retries.