IronMQ Dead Letter Queue Reference

Table of Contents

Overview

A dead letter queue is a queue that other (source) queues can target to send messages that for some reason could not be successfully processed. Dead letter queues can only be used as a target from a pull queue. Messages that have exceeded the allowed number of time outs on the source queue are placed onto the dead letter queue. Messages on the dead letter queue can then be processed again or analyzed to try to determine why they weren’t successfully processed in the first place, without having to throw them away.

A dead letter queue cannot be specified on a push queue, for something similar, see error queues.

Creating a Dead Letter Queue

To add a dead letter queue to a queue, use the create or update queue endpoint:

PUT /3/projects/:project/queues/:queue

{"queue":{"dead_letter":{"queue_name":"deadies", "max_reservations":1}}}

"queue_name" must be a non-empty string in order to create a dead letter queue, otherwise the request will error unless the queue already has a dead letter queue defined on it. "max_reservations" can be specified if desired to be a value 1 <= max_reservations <= 1000, and will default to 10 if omitted. If a queue with the given dead letter queue name already exists, it’s used as is. Otherwise, a new queue is automatically created with the default pull queue settings.

Removing a Dead Letter Queue

In order to turn off the dead letter queue feature on a queue, the user should use the update queue endpoint with an empty "queue_name" in the "dead_letter" field:

PUT /3/projects/:projects/queues/:queue

{"queue":{"dead_letter":{"queue_name":""}}}

The response will be a queue without a "dead_letter" section, if successful. This action will not remove the messages on the queue or delete the queue previously at "queue_name". The only consequence of this action is that messages will no longer be sent from the source queue to the dead letter queue.

Behavior

Upon addition of a dead letter queue to a queue’s configuration, any message, including any existing messages on the queue, whose reserved_count field exceeds the dead_letter.max_reservations threshold will be placed onto the queue specified as dead_letter.queue_name under the same project, and removed from the current queue.

The messages are sent to the dead letter queue as is; that is, the message id is the same as the original message from the queue of origin. The reserved_count field is preserved on the dead letter queue, as well. The body of the message also remains unchanged. The id remaining the same should make it easy to correlate events on each message across the original queue and the dead letter queue, if desired. The only field we update is the message expiration is adjusted to the message expiration for the dead letter queue upon insertion into the dead letter queue; i.e. after adding a message to the dead letter queue, the expiration will be extended to 7 days (by default) from that point in time, not the original enqueue time. Since reserved_count is maintained, users should be careful if they have a dead letter queue for their dead letter queue (yo dawg…). Example dlq message for a queue with dead_letter.max_reservations = 10:

queue                       dlq

{                           {
  id: 1234567891011,          id: 1234567891011,
  reserved_count: 10,         reserved_count: 10,
  body: "sup"                 body: "sup"
}                           {

There is only one operation that can spur a message being moved to the dead letter queue, that operation is reserve. Viewing messages in the dashboard or using peek or get will not count against the current reserved_count. Also, simply adding a dead_letter section to a queue will not in itself make messages move to the dead letter queue, only from reserving once we come across any messages that meet the criterion.

reserved_count is a field on each message that will be incremented each time a message is returned from reserve with the current reservation count, including the reservation which took place to return it from reserve; i.e., the first reservation of a message will have msg.reserved_count = 1. touch is the only other operation that modifies msg.reserved_count, however, touch causing reserved_count to exceed the dead_letter.max_reservations threshold will not cause the message to be moved to the dead letter queue immediately, only after we come across the message in reserve.

Since queues may exist across nodes, we cannot guarantee delivery of messages to the dead letter queue and both progress on the current queue. This means that during certain failure scenarios (such as the dead letter queue having no replicas online) we prefer to make progress on the main queue and can drop messages that were intended to go to the dead letter queue. The expectation is that this is rare, and only during failure scenarios, but here is a disclaimer that it can happen. This also means that there is a slight latency penalty on reserve once we do come across any messages that meet the dead letter queue criterion; in nominal usage having a dead letter queue specified doesn’t affect performance. If this policy is unacceptable, users can do a similar check of msg.reserved_count and do whatever they please with each message.

One Time Delivery Use Case

The all hailed one time delivery for messages in a queueing system can be imitated using a dead letter queue, if desired, by setting dead_letter.max_reservations = 1.

Doing so will mean that the message can only be reserved one time on the original queue, and any successive attempts to reserve the message will result in the message being moved to the dead letter queue. The message then exists on the dead letter queue and the second, third, etc deliveries can be handled differently by consumers / by different consumers.

This can also be done simply by checking the reserved_count on each message even without the dead letter queue specified, but the dead letter queue makes this easier for consumers if they would like to use it.