Publish-Subscribe Channel
The dual of point-to-point: instead of an exclusive receiver, several independent subscribers each receive their own copy of the message. The model for internal hub events and the technical foundation of multi-recipient B2B broadcast.
Problem
A business event — an invoice validation, an order confirmation, a catalogue update — concerns several parties: the warehouse that must prepare, accounting that must record, the supplier portal that must display, the data warehouse that must index. If the emitter has to call each one explicitly, the graph becomes a brittle star. Coupling grows with every new interested party. A broadcast channel is needed: the emitter publishes once, the channel redistributes to all subscribers.
Forces
- Producer decoupling. The producer does not know the subscriber list; it publishes on the topic.
- Extensibility. Adding a consumer = subscribing to the topic, no producer change.
- Independent copies. Each subscriber has its own read pointer / offset. Consumption by A does not affect B.
- High-cost fan-out. The channel duplicates the payload for N subscribers. Combine with Claim Check for large payloads.
Solution
EIP §106 (Hohpe & Woolf, 2003) defines the Publish-Subscribe Channel as a broadcasting channel: each published message is delivered to every current subscriber. The classic implementation is a topic (Kafka, RabbitMQ fanout exchange, JMS Topic, AWS SNS, Azure Service Bus topic). Each subscription keeps its own progress state: one subscriber can fall behind without blocking others; it can be reset to replay history without re-emission.
one publisher N independent subscribers
───────────── ────────────────────────
┌─▶ subscriber A (warehouse)
│
┌──────────┐ ┌──────────┐ │
│ producer │ ──▶│ topic │ ─────┼─▶ subscriber B (accounting)
└──────────┘ └──────────┘ │
│
└─▶ subscriber C (analytics)
Each subscriber gets its own copy; ack of A doesn't drop B/C. EDI implementation
- SBDH UBL routed to multiple PEPPOL APs. In B2G e-invoicing, a UBL invoice wrapped in an SBDH (Standard Business Document Header, ISO/IEC 15000-5) can be addressed simultaneously to the buyer's Access Point and to a tax authority AP (5-corner model). The emitting hub publishes once; the PEPPOL network routes to both destinations.
- Internal hub events. A Kafka topic
edi.events.invoic.validatedis published by the validator; three consumers subscribe: the router that pushes the invoice to the partner, the KPI engine that updates the dashboard, the notification service that mails the operator. None know the other two exist. - PRICAT catalogue broadcast. A supplier publishes a catalogue update (EDIFACT PRICAT or GS1 Catalog) that must reach 12 different retailer chains. Broadcast on internal topic, the outbound router pushes to each retailer on its respective point-to-point channel.
- GLN-based notifications. A "delivery recorded" event (DESADV/ASN received and validated) is broadcast to all applications subscribing by recipient GLN: supplier portal, ERP, GS1 tracer.
<?xml version="1.0" encoding="UTF-8"?>
<StandardBusinessDocument xmlns="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader">
<StandardBusinessDocumentHeader>
<HeaderVersion>1.0</HeaderVersion>
<Sender>
<Identifier Authority="iso6523-actorid-upis">0088:5798000000122</Identifier>
</Sender>
<Receiver>
<Identifier Authority="iso6523-actorid-upis">0088:7300010000001</Identifier>
</Receiver>
<DocumentIdentification>
<Standard>urn:oasis:names:specification:ubl:schema:xsd:Invoice-2</Standard>
<TypeVersion>2.1</TypeVersion>
<InstanceIdentifier>inv-202605140001</InstanceIdentifier>
<Type>Invoice</Type>
<CreationDateAndTime>2026-05-14T12:00:00Z</CreationDateAndTime>
</DocumentIdentification>
</StandardBusinessDocumentHeader>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<!-- UBL payload -->
</Invoice>
</StandardBusinessDocument> Reading: the SBDH declares a single sender but the SBDH + PEPPOL AP coupling allows the same UBL payload to be routed to several recipients (buyer + administration), each receiving its copy. Corner 5 (tax authority in CTC mode, Italy, Poland, France) is typically an additional subscriber on the publish-subscribe channel.
Durable vs. transient subscriptions
Two modes by criticality:
- Durable. The subscription persists even if the consumer is disconnected; messages accumulate in its buffer until resume. Mandatory in business EDI (loss = uninvoiced).
- Transient (non-durable). The subscription lives with the consumer: if disconnected, missed messages are lost. Only acceptable for purely informational flows (logs, telemetry).
Anti-patterns
- Pub-sub where point-to-point suffices. If there is one recipient, use a queue. A one-subscriber topic adds duplicated throughput uselessly and breaks uniqueness guarantees.
- Transient subscription for business flow. The first restart loses messages received during the outage. In B2B, always durable.
- Huge payload without claim check. Broadcasting 10 MB to 12 subscribers = 120 MB of network and storage. Externalise the payload to S3 + broadcast a reference.
- Order assumed across subscribers. One subscriber may lag minutes behind another. Do not logically couple two subscribers via the topic's timing.
Related patterns
- Message Channel — the generalisation.
- Point-to-Point Channel — the exclusive alternative.
- Wire Tap — an observer subscriber grafted onto an existing channel.
- Claim Check — to avoid duplicating the payload N times.
Sources
- Hohpe G., Woolf B. — Enterprise Integration Patterns, Publish-Subscribe Channel (§106). enterpriseintegrationpatterns.com — Publish-Subscribe Channel
- ISO/IEC 15000-5 — ebXML Core Components Technical Specification, which formalises the Standard Business Document Header (SBDH) used by OpenPEPPOL to identify sender and recipient(s).
- OpenPEPPOL — PEPPOL Network Architecture. The 4-corner (and its 5-corner CTC extension) model relies on publish-subscribe addressing by participant ID. docs.peppol.eu/edelivery
- Apache Kafka — Documentation. The Kafka topic is the modern reference implementation of the pattern, with per-consumer-group offsets. kafka.apache.org/documentation