Menu Search

9.4. Handing Undeliverable Messages

9.4.1. Introduction

Messages that cannot be delivered successfully to a consumer (for instance, because the client is using a transacted session and rolls-back the transaction) can be made available on the queue again and then subsequently be redelivered, depending on the precise session acknowledgement mode and messaging model used by the application. This is normally desirable behaviour that contributes to the ability of a system to withstand unexpected errors. However, it leaves open the possibility for a message to be repeatedly redelivered (potentially indefinitely), consuming system resources and preventing the delivery of other messages. Such undeliverable messages are sometimes known as poison messages.

For an example, consider a stock ticker application that has been designed to consume prices contained within JMS TextMessages. What if inadvertently a BytesMessage is placed onto the queue? As the ticker application does not expect the BytesMessage, its processing might fail and cause it to roll-back the transaction, however the default behavior of the Broker would mean that the BytesMessage would be delivered over and over again, preventing the delivery of other legitimate messages, until an operator intervenes and removes the erroneous message from the queue.

Qpid has maximum delivery count and dead-letter queue (DLQ) features which can be used in concert to construct a system that automatically handles such a condition. These features are described in the following sections.

9.4.2. Maximum Delivery Count

Maximum delivery count is an attribute of a queue. If a consumer application is unable to process a message more than the specified number of times, then the Broker will either route the message via the queue's alternate binding (if one has been defined), or will discard the message.

When using AMQP 1.0 the current delivery count of a message is available to the consuming application via the message-count message header (exposed via the JMSXDeliveryCount JMS message property when using JMS). When using the AMQP 0-8..0-10 protocols this information is not available.

Note

When using AMQP 0-8..0-10, in order for a maximum delivery count to be enforced, the consuming application must call Session#rollback() (or Session#recover() if the session is not transacted). It is during the Broker's processing of Session#rollback() (or Session#recover()) that if a message has been seen at least the maximum number of times then it will move the message to the DLQ or discard the message. If the consuming application fails in another manner, for instance, closes the connection, the message will not be re-routed and consumer application will see the same poison message again once it reconnects.

If the consuming application is using Qpid JMS Client 0-x and using AMQP 0-8, 0-9, or 0-9-1 protocols, it is necessary to set the client system property qpid.reject.behaviour or connection or binding URL option rejectbehaviour to the value server.

9.4.3. Alternate Binding

Once the maximum delivery count is exceeded, if the queue has an alternateBinding specified, the Broker automatically routes the message via the alternate binding. The alternate binding would normally specify a queue designated for that purpose of receiving the undeliverable messages. By convention such queues are known as dead-letter queues or simply DLQs.

It is possible to configure the broker to automatically default a DLQ for every queue created. To do this one can set the context variable queue.defaultAlternateBinding at the Virtual Host (or above) level. For example, by setting the value to {\"destination\": \"$${this:name}_DLQ\"} a new queue exampleQueue will default to having an alternate binding to exampleQueue_DLQ. To avoid error this should be combined with setting a node auto creation policy on the VirtualHost, so that such DLQs are automatically created, e.g.

   "nodeAutoCreationPolicies" : [ {
   "pattern" : ".*_DLQ",
   "nodeType" : "Queue",
   "attributes" : {
   "alternateBinding" : ""
   },
   "createdOnPublish" : true,
   "createdOnConsume" : true
   } ]
  

Note

For the autocreated DLQs it is important to override the default alternate binding, as above, else the creation of an infinite chain of DLQs for DLQs will be attempted.

Avoid excessive queue depth

Applications making use of DLQs should make provision for the frequent examination of messages arriving on DLQs so that both corrective actions can be taken to resolve the underlying cause and organise for their timely removal from the DLQ. Messages on DLQs consume system resources in the same manner as messages on normal queues so excessive queue depths should not be permitted to develop.