Collecting Unroutable Messages in a RabbitMQ Alternate Exchange

No matter how careful you are, mistakes can happen. For example, a client may accidentally or maliciously route messages using non-existent routing keys. To avoid complications from lost information, collecting unroutable messages in a RabbitMQ alternate exchange is an easy, safe backup.

In this article, we describe how to set up and use alternate exchanges.

Issues with Unrouted Messages

Unroutable messages are an issue. They slow down processing times if applications make multiple attempts at delivery or are kept busy by continually logging them. Additionally, there is what to do with unrouted messages, which must eventually be handled or dropped.

Whether messages returns or not, unroutable messages can:

  • Be returned to a broken application that constantly resends them.
  • Be the result of malicious activity aimed at causing RabbitMQ to become unresponsive.
  • Cause the loss of mission-critical data

As an example, think of a hospital that uses RabbitMQ to help store patient information in a database. Medical devices typically push vital data to a small server for processing, which then forwards the information to the cloud for storage. In this case, RabbitMQ can be used to push data to the cloud and be employed to facilitate streaming.

Should messages drop before they end up in RabbitMQ, doctors could lose vital information. This loss could impact diagnosis and treatment. The situation could become even worse if the system breaks and overloads the resources handling messages related to more than one patient.

What happens to unroutable messages in RabbitMQ?

It is possible to avoid the complete loss of a message. RabbitMQ handles unroutable messages in two ways based on the mandatory flag setting within the message header. The server either returns the message when the flag is set to true or silently drops the message when set to false.

Applications can log returned messages, but logging does not provide a mechanism for dealing with an unreachable exchange or queue.

Avoid Data Loss with a RabbitMQ Alternate Exchange

RabbitMQ also lets you define an alternate exchange to apply logic to unroutable messages. Set an alternate exchange using policies or within arguments when declaring an exchange.

The alternate exchange attaches to one or more primary exchanges. Set the exchange type to fanout to ensure that rejected messages always route to the alternate queue. Be advised that there is no way to catch invalid exchange names outside of the mandatory flag.

Creating the Alternate Exchange

Defining an alternate exchange is no different than defining any other part of your topology. The primary exchange forwards the message to the alternate exchange, which sends it to the alternate queues.

Create a fanout exchange and attach a queue:

conn_str = os.environ["AMQP_URI"]
params = pika.URLParameters(conn_str)
connection = pika.BlockingConnection(params)
channel = connection.channel()

channel.exchange_declare("alt_exchange", "fanout")
channel.queue_declare("alt_queue")
channel.queue_bind("alt_queue", "alt_exchange")

Full sample code can be found at GitHub.

Make sure that the alternate queue is attached to the exchange through the RabbitMQ API. You can use the API provided by RabbitMQ to list bindings:

http://localhost:15672/api/exchanges/test_vhost/primary_exchange

Change the URL to match your host and port. Additionally, enable the RabbitMQ management console.

Any message sent to the alt_exchange winds up in the alt_queue. Since we use a fanout exchange, the message ends up in all queues attached to alt_exchange.

Attaching the Alternate Exchange

Use policies, the UI, or message headers to set the alternate exchange. You must use the command line to attach an alternate exchange after declaring the primary exchange.

You can use message arguments to set the exchange:

args = {"alternate-exchange": "alt_exchange"}
channel.exchange_declare("primary_exchange", "direct", arguments=args)

Alternately, use the command line to specify the alternate exchange:

rabbitmqctl set_policy AE “primary_*” ‘{“alternate-exchange”: “alt_exchange”}’

RabbitMQ sends all messages from the primary_exchange to the alt_exchange when the routing key is invalid. Unrouted messages end up in the alt_queue.

What happens when the mandatory flag is set with an alternate exchange?

There is still a chance that messages won’t be routed if an alternate exchange is provided. The service may be unreachable, or the alternate queue may not be specified correctly. You might accidentally specify a non-existent exchange as well.

Setting the mandatory flag will catch these unrouted messages. Keep in mind that, if the message routes to the alternate exchange, RabbitMQ marks the message as delivered.

Happy coding!

CloudAMQP - industry leading RabbitMQ as a service

Start your managed cluster today. CloudAMQP is 100% free to try.

13,000+ users including these smart companies