RabbitMQ Topic Exchange

The topic exchange is the most flexible exchange type in RabbitMQ. It routes messages based on wildcard pattern matching against the routing key. Instead of requiring an exact match like a direct exchange, or ignoring the key entirely like a fanout exchange, the topic exchange lets queues subscribe to categories of messages using patterns.

The Newspaper Subscription Analogy

A newspaper publisher offers sections: Sports, Finance, Technology, Local, International. Readers can subscribe to exactly the sections they want. One reader subscribes to all Sports articles. Another subscribes to all International Finance stories. A third wants everything. The topic exchange works the same way — queues subscribe to patterns, and messages are delivered only to matching queues.

Routing Key Format

Topic exchange routing keys are dot-separated words. For example:

  • order.placed.usa
  • payment.failed.europe
  • log.error.database
  • sensor.temperature.building1

Each word segment represents a category level. The exchange uses these segments to match binding patterns.

Wildcard Characters

Topic exchange binding patterns support two wildcards:

  • * (asterisk) — matches exactly one word in that position
  • # (hash) — matches zero or more words
Pattern          Matches                         Does NOT Match
-----------------------------------------------------------------
order.*          order.placed                    order.placed.usa
                 order.cancelled                 order

order.#          order.placed                    payment.placed
                 order.placed.usa
                 order

*.error.*        log.error.db                    error.db
                 app.error.network               log.error

#                everything (catch-all)          (nothing)

log.#            log                             app.log
                 log.error
                 log.error.database

Topic Exchange Routing Diagram

[Topic Exchange: "app-events"]
   |
   +-- binding: "order.#"      --> [order-team-queue]
   |
   +-- binding: "*.error.*"    --> [error-alert-queue]
   |
   +-- binding: "payment.*"    --> [payment-queue]
   |
   +-- binding: "#"            --> [audit-log-queue]

Message: routing_key = "order.placed.usa"
  --> order-team-queue   ✓  (matches "order.#")
  --> audit-log-queue    ✓  (matches "#")
  --> error-alert-queue  ✗  (does not match "*.error.*")
  --> payment-queue      ✗  (does not match "payment.*")

Message: routing_key = "payment.failed"
  --> payment-queue      ✓  (matches "payment.*")
  --> audit-log-queue    ✓  (matches "#")
  --> order-team-queue   ✗  (does not match "order.#")
  --> error-alert-queue  ✗  (does not match "*.error.*")

Topic Exchange as Direct Exchange

If you use no wildcards in your binding patterns, a topic exchange behaves exactly like a direct exchange. A pattern of payment.success only matches a routing key of exactly payment.success.

Topic Exchange as Fanout Exchange

If you use # as the only binding pattern, the queue receives every message regardless of routing key. This replicates fanout behaviour.

Real-World Use Case: IoT Sensor Network

A factory has hundreds of sensors. Each sensor publishes messages with routing keys in this format:

<building>.<floor>.<sensor-type>

Examples: buildingA.floor3.temperature, buildingB.floor1.humidity

[Topic Exchange: "factory-sensors"]
   |
   +-- "buildingA.#"            --> [building-a-team-queue]
   |   (all sensors in building A)
   |
   +-- "*.*.temperature"        --> [temp-monitor-queue]
   |   (all temperature sensors everywhere)
   |
   +-- "buildingB.floor1.*"     --> [floor1b-queue]
   |   (all sensors on floor 1 of building B)
   |
   +-- "#"                      --> [central-log-queue]
       (everything)

A message from buildingA.floor2.temperature goes to building-a-team-queue, temp-monitor-queue, and central-log-queue.

Setting Up a Topic Exchange

In Python using pika:

# Declare exchange
channel.exchange_declare(exchange='app-events', exchange_type='topic')

# Declare queue and bind with pattern
channel.queue_declare(queue='order-queue', durable=True)
channel.queue_bind(
    exchange='app-events',
    queue='order-queue',
    routing_key='order.#'
)

# Producer publishes
channel.basic_publish(
    exchange='app-events',
    routing_key='order.placed.eu',
    body='{"order_id": 9901}'
)

Choosing Between Direct, Fanout, and Topic

Need exact routing?         --> Direct Exchange
Need to broadcast all?      --> Fanout Exchange
Need pattern-based routing? --> Topic Exchange

In practice, topic exchanges cover the widest range of real-world scenarios. Most production systems with multiple event types use a topic exchange as their main routing hub.

Summary

The topic exchange routes messages using dot-separated routing keys matched against wildcard binding patterns. The * wildcard matches one word. The # wildcard matches zero or more words. Topic exchanges combine the precision of direct exchanges with the flexibility of fanout exchanges. They are the best choice when your messaging system has multiple event categories that different consumers need to subscribe to selectively.

Leave a Comment

Your email address will not be published. Required fields are marked *