RabbitMQ Headers Exchange Explained
Headers Exchange in RabbitMQ routes messages using message headers to route messages. Let’s explore how Header Exchanges work in RabbitMQ, underlying concepts and see it in action from a .NET application.
Table of Contents
Headers Exchange in RabbitMQ routes messages using message headers to route messages.
A message is considered a match if the header's value matches that on the binding.
In this post, let’s explore
- RabbitMQ Headers Exchanges
- Underlying Concepts of Headers Exchange
- Headers Exchange in action from a .NET application.
I use Amazon MQ, a managed message broker service that supports ActiveMQ and RabbitMQ engine types, to host my RabbitMQ instance. However, you can use one of the various options that RabbitMQ provides to host your instance.
This article is sponsored by AWS and is part of my RabbitMQ Series.
What is a RabbitMQ Headers Exchange?
Headers Exchange in RabbitMQ uses message header attributes to route messages.
Since a message can contain more than one header value, Headers Exchange supports routing on multiple attributes.
Headers Exchange is referred to as a 'Direct Exchange on steroids'
With Headers Exchange, we are not limited to one routing key but use multiple header keys to specify the binding.
When a message is sent, the Sender also populates header attributes.
The headers property is a key/value table allowing user-defined keys and values.
The Receiver sets up the Queue and the associated Bindings on the Queue.
Any or All Match on Header Attributes
The Binding can be set up to match all or any one of the Header attributes on the message. This means that the message is considered a match only when all the header attributes are an exact match or any one of the attributes matches.
The x-match
attribute on the Binding is used to specify this.
- all → matches all header values
- any → matches any one header value
Message Routing in RabbitMQ Headers Exchange
When a message is sent to the Headers exchange it inspects the header attributes on the message and that on the binding to decide which Queues to send a copy of the message to.
Depending on the x-match
binding attribute, it either compares all the header attributes and any one of the attributes to create a match.
In the above scenario, the message has two header attributes location
and temperature
with values of 'sydney' and 25.
Since the first binding (from the left) has an x-match
value set to all
and the location
and temperature
header values specified match that on the message it gets sent to that queue.
The second binding (middle one) has an x-match
set to all
and only one header, location
specified with a value of brisbane
. Since it does not match with that on the message, that queue does not receive a copy of the message.
The third binding has the x-match
of any
and has the location
set to 'brisbane' and the temperature
to 25. In this case, since one of the headers, temperature
, matches that on the message, a copy of the message is sent to the queue.
RabbitMQ Headers Exchange From .NET
We will use a NuGet package, RabbitMQ.Client, to connect and send/receive messages from RabbitMQ.
If you are new to building RabbitMQ from .NET applications, check out the Getting Started article below.
Create and Send Messages to Headers Exchange From .NET
Exchanges are created using the Channel.
The ExchangeDeclare
the method takes in an exchange name and its type. Below is an example of creating a RabbitMQ Headers Exchange in .NET.
var factory = new ConnectionFactory()
{
Uri = new Uri("YOUR RABBIT INSTANCE URI"),
Port = 5671,
UserName = "<USERNAME FROM CONFIGURATION FILE>",
Password = "<PASSWORD FROM CONFIGURATION FILE>"
};
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
var exchangeName = "weather_headers";
channel.ExchangeDeclare(exchangeName, ExchangeType.Headers);
When sending a message, the sender specifies the Exchange, message body, and message headers.
var basicProps = channel.CreateBasicProperties();
basicProps.Headers = new Dictionary<string, object>()
{
{"location", location},
{"temperature", temperature}
};
channel.BasicPublish(exchangeName, routingKey, basicProps, body);
The above code uses the CreateBasicProperties
method on the channel to construct the instance to add in the Headers.
The routingKey
is ignored in the case of Headers Exchange. You can pass that as an empty string.
Set up Binding on RabbitMQ Headers Exchange From .NET
Messages are routed to Queues from Exchanges using the Binding information.
To create a Queue, use the QueueDeclare
method. It will create a new Queue only if one doesn't exist with the same name.
var factory = new ConnectionFactory()
{
Uri = new Uri("YOUR RABBIT INSTANCE URI"),
Port = 5671,
UserName = "<USERNAME FROM CONFIGURATION FILE>",
Password = "<PASSWORD FROM CONFIGURATION FILE>"
};
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
channel.QueueDeclare(queueName, false, false, false, null);
var bindingHeaders = new Dictionary<string, object>()
{
{"x-match", match},
{"location", location}
};
if (!string.IsNullOrEmpty(temperature))
bindingHeaders.Add("temperature", temperature);
channel.QueueBind(queueName, "weather_headers", routingKey:string.Empty, bindingHeaders);
The above code sets up the Binding using the QueeuBind
method on the channel passing in the queueName
, exchangeName
and also the binding headers.
Once the Sender and Receiver applications are running, you can see the Exchange and its details in the RabbitMQ Management console.
Below is the snapshot of the weather_headers
exchange, with three Bindings set up and the associated binding headers set up.
You can find the complete source code for this blog post sample here.
Rahul Nath Newsletter
Join the newsletter to receive the latest updates in your inbox.