Search code examples
pythonrabbitmqpikapython-pika

RabbitMQ headers binding is not working as expected, Header exchange is routing message to all the bound queues


I want to route rabbitmq messages based on headers and I have created a appropriate infrastructure including headers exchange, queues, bindings etc. Below is the complete code for the consumer.py

import pika

# define variables
url = "amqp://rabbitmq-host/"
exchange = 'headers-exchange',
s_queue = 'StudentQueue'
t_queue = 'TeacherQueue'

# create connection
connection_parameters = pika.URLParameters(url)
connection = pika.BlockingConnection(connection_parameters)
channel = connection.channel()

# declare exchange
channel.exchange_declare(
    exchange=exchange,
    exchange_type='headers',
    durable=True
)

# declare student queue
channel.queue_declare(
    queue=s_queue,
    durable=True,
)
# bind student queue
channel.queue_bind(
    exchange=exchange,
    queue=s_queue,
    # bind arguments:
    # match all the given headers
    # match x-queue should be equal to student
    arguments={
        "x-match": "all",
        "x-queue": "student"
    },
)

# declare teacher queue
channel.queue_declare(
    queue=t_queue,
    durable=True,
)
# bind teacher queue
channel.queue_bind(
    exchange=exchange,
    queue=t_queue,
    # bind arguments:
    # match all the given headers
    # match x-queue should be equal to teacher
    arguments={
        "x-match": "all",
        "x-queue": "teacher"
    },
)

and publish module(publish.py) looks like below:

import datetime
import time
import uuid
import pika

# define variables
url = "amqp://rabbitmq-host/"
exchange = 'headers-exchange',

# create connection
connection_parameters = pika.URLParameters(url)
connection = pika.BlockingConnection(connection_parameters)
channel = connection.channel()

# declare exchange
channel.exchange_declare(
    exchange=exchange,
    exchange_type='headers',
    durable=True
)

# define message id
id_ = uuid.uuid4()
message_id = id_.hex
timestamp = time.mktime(datetime.datetime.now().timetuple())                                                     


# define message property esp. headers
properties = pika.BasicProperties(
    content_type="application/json",
    # match x-queue = student header
    # to the StudentQueue
    headers={"x-queue": "student"}
    message_id=message_id,
    timestamp=timestamp,
    delivery_mode=2,
)

# publish the message for student queue
channel.basic_publish(
    exchange=exchange,
    routing_key="",
    body="for student queue only",
    properties=properties,
)

published message should only be delivered to StudentQueue because we have headers={"x-queue": "student"} but it is getting delivered to TeacherQueue as well which is incorrect.

the list of appication versions are:

RabbitMQ: 3.6.16
Erlang: 20.3.4
Pika: 1.2.1

Could someone point the obvious which I have missed, could it be related to mismatched versions? Any help would be really appreciated.

Cheers, DD.


Solution

  • From the documentation:

    For "any" and "all", headers beginning with the string x- will not be used to evaluate matches.

    Therefore, in your example in both binding argument and message header change "x-queue": "teacher" to "queue": "teacher" (but still leave binding argument "x-match": "all" as-is).