The RabbitMQ transport has the concept of a routing topology, which controls how it creates exchanges, queues, and the bindings between them in the RabbitMQ broker. The routing topology also controls how the transport uses the exchanges it creates to send and publish messages. All endpoints in a system must use the same topology to be able to communicate with each other. For new systems, the conventional routing topology should be used. The direct routing topology is recommended only when adding an endpoint to an existing system that already uses that topology. A custom topology can be useful when integrating with a legacy system.
Conventional routing topology
The conventional routing topology relies on fanout exchanges to route messages.
Sending using the conventional routing topology
Each endpoint creates a pair of a fanout exchange and a queue named after the endpoint's name. It also creates a binding between them. Messages are sent to the endpoint by publishing them to the endpoint's exchange. The binding then routes the message to the endpoint's queue.
Publishing using the conventional routing topology
For each type being published, a series of fanout exchanges are created to model the inheritance hierarchy of the type. For each type involved, an exchange is created, named in the following format: Namespace:TypeName
. Bindings are created between the types, going from child to parent, until the entire hierarchy has been modeled. Exchanges are also created for each interface the type implements.
When an endpoint subscribes to an event, it first ensures that the above infrastructure exists. It then adds a binding from the exchange corresponding to the subscribed type to its own exchange.
When an endpoint publishes an event, it first ensures that the above infrastructure exists. It then publishes the message to the exchange corresponding to the message type being published.
Direct routing topology
The direct routing topology routes all events through a single exchange, amq.
by default. Events are published using a routing key based on the event type, and subscribers will use that key to filter their subscriptions.
Sending using the direct routing topology
Every endpoint creates a queue named after the endpoint's name. When an endpoint sends a message it publishes it to a default exchange with a routing key equal to the destination endpoint name. This makes use of RabbitMQ default exchanges to move the message to a queue with the same name.
Publishing using the direct routing topology
Every endpoint publishes an event using the amq.
exchange with a routing key of the form Namespace.
, corresponding to the type of the event. The event is moved to all queues that have a binding for that event type.
An endpoint that subscribes to a given event creates a binding to the default exchange with the appropriate routing key.
Enabling the direct routing topology
To enable the direct routing topology, use the following configuration:
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseDirectRoutingTopology();
Overriding the default conventions
The default conventions for exchange names and routing keys can be overridden by using the following overload:
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseDirectRoutingTopology(
routingKeyConvention: MyRoutingKeyConvention,
exchangeNameConvention: (address, eventType) => "MyTopic");
Controlling exchange and queue durability
The routing topologies provided by the transport will create durable exchanges and queues unless durable messages have been disabled globally for the endpoint. Transient exchanges and queues will be created when DisableDurableMessages
is called.
Custom routing topology
If the built-in routing topologies do not satisfy the requirements of the system, a custom routing topology may be used. To do this:
- Define the routing topology by creating a class implementing
IRoutingTopology
. - Register it with the transport calling
UseRoutingTopology
as shown below.
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseRoutingTopology(
topologyFactory: createDurableExchangesAndQueues =>
{
return new MyRoutingTopology(createDurableExchangesAndQueues);
});
The boolean argument supplied to the factory delegate indicates whether the custom routing topology should create durable exchanges and queues on the broker. Read more about durable exchanges and queues in the AMQP Concepts Guide.
UseRoutingTopology
shown below is still supported in NServiceBus.RabbitMQ version 4.x, but it is marked as [Obsolete]
with a warning. It is not available in version 5.0 and above.var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseRoutingTopology<MyRoutingTopology>();
For each queue required by the endpoint, the transport will first declare that queue and will then call the Initialize
method of the routing topology. The routing topology should then perform all initialization related to that specific queue such as the creation of appropriate exchanges and bindings.
Taking control of queue declaration
In NServiceBus.RabbitMQ versions 4.2 and above, custom routing topologies can take control of queue declaration by implementing IDeclareQueues
in addition to IRoutingTopology
in the routing topology class.
When the routing topology implements IDeclareQueues
, the transport will not declare queues, and it will call the DeclareAndInitialize
method of the routing topology instead of calling the Initialize
method. The routing topology is then responsible for creating the queue and any exchanges, bindings and extra queues which are required for that queue to operate. The Initialize
method of the routing topology will not be called.
IRoutingTopology
and IDeclareQueues
have been combined into a single interface in NServiceBus.RabbitMQ versions 5 and above.
Delayed delivery
In Versions 4.3 and above, custom routing topologies can support delayed delivery without requiring the timeout manager by implementing ISupportDelayedDelivery
in addition to IRoutingTopology
in the routing topology class.
When the routing topology implements ISupportDelayedDelivery
, the transport will call the BindToDelayInfrastructure
method to allow the routing topology to create the appropriate bindings to the delivery exchange that is part of the native delayed delivery infrastructure.
IRoutingTopology
and ISupportDelayedDelivery
will be combined into a single interface in Version 5.0.