Headers Exchange — Complete Guide
In this tutorial, you will learn about Headers Exchange. We cover key concepts, practical examples, and best practices to help you master this topic.
A headers exchange routes messages based on header attributes instead of routing keys, using x-match all/any for flexible attribute-based routing.
Headers Exchange Flow
flowchart LR
P[Publisher] --> H[Headers Exchange]
H -->|"x-match: all
format=json, source=partner"| Q1[Partner JSON]
H -->|"x-match: any
priority=high"| Q2[Priority Queue]
style H fill:#f90,color:#fff
import pika
import json
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='header_router', exchange_type='headers', durable=True)
channel.queue_declare(queue='partner_json', durable=True)
channel.queue_declare(queue='priority_msgs', durable=True)
channel.queue_declare(queue='csv_archive', durable=True)
channel.queue_bind(
exchange='header_router', queue='partner_json',
arguments={'x-match': 'all', 'format': 'json', 'source': 'partner'}
)
channel.queue_bind(
exchange='header_router', queue='priority_msgs',
arguments={'x-match': 'any', 'priority': 'high', 'source': 'partner'}
)
channel.queue_bind(
exchange='header_router', queue='csv_archive',
arguments={'x-match': 'all', 'format': 'csv'}
)
messages = [
({'format': 'json', 'source': 'partner', 'priority': 'high'}, 'Partner JSON data'),
({'format': 'csv', 'source': 'internal', 'priority': 'low'}, 'Internal CSV report'),
({'format': 'xml', 'source': 'partner', 'priority': 'high'}, 'Partner XML feed'),
]
for headers, body in messages:
channel.basic_publish(
exchange='header_router', routing_key='', body=body,
properties=pika.BasicProperties(headers=headers, delivery_mode=2)
)
print(f"Published with headers: {headers}")
connection.close()
Expected output:
Published with headers: {'format': 'json', 'source': 'partner', 'priority': 'high'}
Published with headers: {'format': 'csv', 'source': 'internal', 'priority': 'low'}
Published with headers: {'format': 'xml', 'source': 'partner', 'priority': 'high'}
x-match: all vs any
x-match: all — All specified headers must match (AND logic) x-match: any — Any one header must match (OR logic)
Header values must match exactly. Missing headers cause x-match: all to fail.
Use Cases
- Routing by content type, format, and source
- Multi-attribute filtering without routing key complexity
- Compatibility with systems that already use message headers
Common Mistakes
1. Forgetting x-match
Without x-match, the binding never matches. Always include x-match with value all or any.
2. Using Headers for Simple Routing
For single-attribute routing, use direct or topic exchange. Headers add unnecessary complexity.
3. Type Mismatches
Headers values are typed. The string 'true' is different from the boolean True. Be consistent.
4. Assuming Headers Match on Absence
Headers exchange matches on presence and value of specified headers. It does not match on headers that are absent.
5. Performance with Many Headers
Each header comparison adds processing time. Keep bindings to 3-5 headers for good performance.
Practice Questions
1. How does headers exchange differ from topic?
Headers exchange matches on arbitrary header attributes. Topic exchange matches on routing key patterns. Headers support AND/OR logic; topic does not.
2. What does x-match=all mean?
All specified header values must match the message headers for routing. If any header is missing or different, the message is not routed.
3. When would you choose headers over topic?
When the routing decision depends on multiple independent attributes. For example, route by format AND source AND priority.
4. Can headers exchange match on header existence alone?
Not directly. You must specify a value. Use a sentinel value like true or exists to match on existence.
Challenge
Design a headers exchange for a document processing pipeline. Documents have type (invoice, report, contract), sensitivity (public, internal, confidential), and language (en, es, fr). Define bindings for automated processing, archival, and manual review.
FAQ
Mini Project: Multi-Attribute Router
import pika, json, threading, time
def start_consumer(name, exchange, binding_args):
conn = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
ch = conn.channel()
ch.exchange_declare(exchange=exchange, exchange_type='headers', durable=True)
q = ch.queue_declare(queue=name, durable=True)
ch.queue_bind(exchange=exchange, queue=q.method.queue, arguments=binding_args)
def cb(c, m, p, body):
print(f"[{name}] {body.decode()} (headers: {p.headers})")
ch.basic_consume(queue=q.method.queue, on_message_callback=cb, auto_ack=True)
ch.start_consuming()
consumers = [
('premium_json', {'x-match': 'all', 'format': 'json', 'tier': 'premium'}),
('any_partner', {'x-match': 'any', 'source': 'partner', 'tier': 'premium'}),
]
for name, args in consumers:
t = threading.Thread(target=start_consumer, args=(name, 'docs', args), daemon=True)
t.start()
time.sleep(1)
conn = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
ch = conn.channel()
ch.exchange_declare(exchange='docs', exchange_type='headers', durable=True)
docs = [
({'format': 'json', 'tier': 'premium', 'source': 'internal'}, 'Premium JSON doc'),
({'format': 'csv', 'tier': 'standard', 'source': 'partner'}, 'Partner CSV doc'),
({'format': 'json', 'tier': 'standard', 'source': 'partner'}, 'Partner JSON doc'),
]
for h, b in docs:
ch.basic_publish(exchange='docs', routing_key='', body=b,
properties=pika.BasicProperties(headers=h, delivery_mode=2))
time.sleep(1)
Expected output:
[premium_json] Premium JSON doc (headers: {'format': 'json', 'tier': 'premium', ...})
[any_partner] Partner CSV doc (headers: {'format': 'csv', ...})
[any_partner] Partner JSON doc (headers: {'format': 'json', ...})
What's Next
Now that you understand headers exchange, explore dead letter exchange for handling failed messages, then learn about message TTL for time-based message expiry.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro