Topic Exchange or Event Bus¶
Topic-keyed routing surface — instantiates Topic-Brokered Event Distribution
The routing core that matches each published event's topic against subscription bindings and delivers a copy to every matching subscriber, without producer and consumer ever naming each other.
A Topic Exchange or Event Bus is the matching engine at the center of the archetype: it takes an event tagged with a topic, compares that topic against every subscription's binding pattern, and hands a copy to each subscriber whose pattern matches. This is the rendezvous the whole design turns on — the producer says what kind of thing happened by naming a topic, the subscriber says what kinds it wants by binding a pattern, and the exchange is the only party that knows both sides. Its defining move is routing on the topic key, not the payload and not a hard-wired recipient list: selection is a match against a stable taxonomy of event kinds, which is what lets a new subscriber appear as one more binding rather than a change to any producer.
Example¶
A hospital's systems publish to a topic hierarchy: lab machines emit to lab.result.hematology, the ED emits admission.ed, pharmacy emits pharmacy.order.stat. Subscribers bind patterns: the clinician results-portal binds lab.result.*, the ED live board binds both admission.ed and lab.result.*, and pharmacy binds pharmacy.order.stat. When a hematology analyzer publishes one result to lab.result.hematology, the exchange matches that key against all bindings and delivers a copy to the results-portal and the ED board — and to nothing else. The analyzer addressed a topic, never the portal; when an infection-control system is added next month, it binds lab.result.microbiology and starts receiving matching results with no change to a single publisher.
How it works¶
- Bindings, not addresses — each subscription registers a topic pattern (exact keys plus wildcards like
lab.result.*); the routing table is the set of these patterns. - Match on the topic key — every published event's topic is tested against the bindings; matching is on the key's structure, cheap and payload-blind.
- Fan-out to the matched set — a copy goes to each matching binding, so one publish becomes N deliveries when N subscriptions match — conditional fan-out, gated by the match.
- Mutual anonymity — producers know only topics, subscribers know only patterns; the exchange is the sole holder of the who-gets-what mapping.
Tuning parameters¶
- Topic hierarchy design — how deep and how granular the taxonomy is; coarse topics force subscribers to over-receive and post-filter, fine ones force them to bind many patterns and risk missing new ones.
- Wildcard semantics — single-segment versus multi-segment wildcards, which set how expressively a subscriber can say "everything under here."
- Routing-versus-filtering split — how much selection is done by the topic key here versus delegated to a payload-level filter downstream.
- Delivery ordering — whether order is preserved across the matched subscribers, and at what throughput cost.
- Binding cardinality limits — how many subscriptions may bind one topic before fan-out becomes a performance concern.
When it helps, and when it misleads¶
Its strength is the decoupling itself: producers and consumers never name each other, and the audience can grow, shrink, or change entirely by editing bindings while every publisher stays untouched. Its failure mode is that the topic taxonomy is nearly a one-way door — once producers and consumers depend on a hierarchy, reshaping it is a coordinated migration, so a taxonomy chosen carelessly early becomes a tax paid forever. The classic misuse is smuggling high-cardinality payload data into the topic key — order.<customerId>.placed — which explodes the routing table and is really content filtering wearing a routing costume[1]. The discipline is to keep topics a stable, low-cardinality vocabulary of event kinds and push per-value selection to a content filter, so the routing surface stays small and durable.
How it implements the components¶
broker_routing_boundary— it is the routing boundary: the table of topic-pattern bindings and the match that decides, for each event, which subscriptions receive it.fan_out_delivery_semantics— it multiplies one matched publish into a copy per matching subscription; this is conditional fan-out, gated by the topic match, as distinct from an unconditional broadcast to all.
It routes and fans out but does not host or secure the intermediary it runs inside (that's Message Broker), broadcast unconditionally to every bound queue regardless of key (that's Fan-Out Exchange), evaluate payload-level predicates (filter_and_selector_rule — that's Content-Based Subscription Filter), or retain events for later replay (replay_and_retention_policy — Replay Log or Event Stream).
Related¶
- Instantiates: Topic-Brokered Event Distribution — it is the broker's routing heart, the rendezvous between topic and subscription.
- Consumes: Message Broker — the trusted intermediary that hosts and runs the exchange.
- Sibling mechanisms: Message Broker · Fan-Out Exchange · Content-Based Subscription Filter · Replay Log or Event Stream · Subscription API
Notes¶
Topic routing and content filtering are complementary layers, not rivals. The exchange narrows by kind using a small, stable set of topic keys; a content filter narrows by value using payload predicates that can be as specific and high-cardinality as needed. Doing value-level selection in the topic key is the single most common way to wreck an event bus — it turns a compact routing table into an unbounded one and freezes per-record logic into the hardest layer to change.
References¶
[1] The topic exchange with wildcard routing keys is the canonical form of this mechanism, standardized in AMQP 0-9-1 (as popularized by RabbitMQ): producers publish with a dotted routing key and consumers bind patterns with * and # wildcards. It is the reference model for routing on a structured topic key rather than on message content or a fixed destination. ↩