I've set up a dead letter routing with my queue to requeue rejected messages with a delay of several seconds, preventing temporary consumer errors to clog up the queue. I've set this up so both the work queue and the dead letter queue are bound to the same exchange:
Externally produced, incoming messages are routed to the exchange, which places them in the work queue. During processing the message, a consumer might fail due to some temporary errors (think a crawler receiving an error 500 from a website).
Instead of rejecting the message and having it placed at the head of the queue again (leading to an infinite loop), we route rejected messages (withrequeue=0
) to the exchange, adding the dead letter queue as the routing key. Here, every message receives a TTL of X seconds, after which it will be rejected, and therefore routed back to the exchange with the routing key se to the original work queue.
However, looking at literature and examples online, everyone seems to recommend routing to a separate dead letter exchange:
Externally produced, incoming messages are routed to the work exchange, which places them in the work queue. If a consumer fails, messages are rejected (with
requeue=0
) and will be routed to the dead letter exchange. The dead letter exchange routes the messages to the dead letter queue, where the message TTL will expire, and the again-rejected messages will be routed back to the work exchange.
Are there some crucial advantage of the second design compared to the first? I cannot identify any, but then again I'm not too confident with RabbitMQ.