Alternate Exchanges


It is sometimes desirable to let clients handle messages that an exchange was unable to route (i.e. either because there were no bound queues or no matching bindings). Typical examples of this are

  • detecting when clients accidentally or maliciously publish messages that cannot be routed
  • "or else" routing semantics where some messages are handled specially and the rest by a generic handler

Alternate Exchange ("AE") is a feature that addresses these use cases.

How to Define an Alternate Exchange

For any given exchange except for the default one, an AE can be defined by clients using policies. This is the recommended option as policies are significantly simplify changes to such options (e.g. during upgrades).

In modern RabbitMQ versions, the default exchange is a special-cased convention in the code and not a "real" exchange. Therefore it does not support the alternate exchange feature.

Alternatively, optional exchange arguments can be provided by client at exchange declaration time. In the case where both policy and arguments specify an AE, the one specified in arguments overrules the one specified in policy.

Configuration Using a Policy

This is the recommended way of defining alternate exchanges.

To specify an AE using policy, add the key 'alternate-exchange' to a policy definition and make sure that the policy matches the exchange(s) that need the AE defined. For example:

rabbitmqctl set_policy AE "^my-direct$" '{"alternate-exchange":"my-ae"}' --apply-to exchanges

Or, on Windows:

rabbitmqctl.bat set_policy AE "^my-direct$" "{""alternate-exchange"":""my-ae""}" --apply-to exchanges

This will apply an AE of "my-ae" to the exchange called "my-direct". Policies can also be defined using the management plugin, see the policy documentation for more details.

Configuration Using Client-provided Arguments

This way of defining an alternate exchange is discouraged. Consider using a policy instead (see above).

When creating an exchange the name of an AE can be optionally supplied in the exchange.declare method's arguments table by specifying a key of 'alternate-exchange' and a value of type 'S' (string) containing the name.

When an AE has been specified, in addition to the usual configure permissions on the declared exchange, the user needs to have read permissions on that exchange and write permissions on the AE.

For example:

Map<String, Object> args = new HashMap<String, Object>();
args.put("alternate-exchange", "my-ae");
channel.exchangeDeclare("my-direct", "direct", false, false, args);
channel.exchangeDeclare("my-ae", "fanout");
channel.queueBind("routed", "my-direct", "key1");
channel.queueBind("unrouted", "my-ae", "");

In the above fragment of Java code we create a direct exchange 'my-direct' that is configured with an AE called 'my-ae'. The latter is declared as a fanout exchange. We bind one queue 'routed' to 'my-direct' with a binding key of 'key1', and a queue 'unrouted' to 'my-ae'.

How Alternate Exchanges Work

Whenever an exchange with a configured AE cannot route a message to any queue, it publishes the message to the specified AE instead. If that AE does not exist then a warning is logged. If an AE cannot route a message, it in turn publishes the message to its AE, if it has one configured. This process continues until either the message is successfully routed, the end of the chain of AEs is reached, or an AE is encountered which has already attempted to route the message.

For example if we publish a message to 'my-direct' with a routing key of 'key1' then that message is routed to the 'routed' queue, in accordance with the standard AMQP behaviour. However, when publishing a message to 'my-direct' with a routing key of 'key2', rather than being discarded the message is routed via our configured AE to the 'unrouted' queue.

The behaviour of an AE purely pertains to routing. If a message is routed via an AE it still counts as routed for the purpose of the 'mandatory' flag, and the message is otherwise unchanged.

Getting Help and Providing Feedback

If you have questions about the contents of this guide or any other topic related to RabbitMQ, don't hesitate to ask them using GitHub Discussions or our community Discord server.

Help Us Improve the Docs <3

If you'd like to contribute an improvement to the site, its source is available on GitHub. Simply fork the repository and submit a pull request. Thank you!