Channels & Routing
How messages find their destination — named channels, wildcard subscriptions, and multicast routing that fans one publish out to many channels.
Think of a channel like the address on an envelope. You do not hand a letter directly to a person — you drop it in the mail with an address, and the postal system delivers it to whoever picks up mail at that address. Senders and receivers never need to know about each other; they only need to agree on the address.
A channel is that address: a named destination that a broker uses to route messages. Publishers send to a channel name; subscribers express interest in a channel name. The broker connects the two. This indirection is what makes messaging loosely coupled — you can add, remove, or move services without either side changing the other's code.
Channels — the idea
A channel is just a string name, chosen by you. Publishers attach that name to each message; the broker matches it against the names subscribers asked for and delivers accordingly. Nothing is hard-wired — the channel is created the moment something uses it.
Good channel names follow a hierarchy, read left to right from broad to specific, with a separator between each level. A common convention is {domain}.{entity}.{action}:
orders.created
orders.updated
orders.us-east.created
payments.completed
inventory.reservedThat hierarchy is not decoration. It is what makes the next idea — wildcards — possible.
Channels are named destinations; the broker matches a publisher's channel name to the subscribers that asked for it.
Wildcards — subscribing to a pattern
Naming channels one by one works until you have dozens of them. A monitoring service that needs every order event would have to subscribe to orders.created, orders.updated, orders.shipped, and remember to add a new subscription every time someone invents orders.cancelled.
A wildcard subscription solves this: instead of naming exact channels, the subscriber names a pattern, and the broker delivers every message whose channel matches. The hierarchy makes the pattern meaningful — each level can be matched broadly or exactly.
Two wildcard tokens are common, and KubeMQ uses both:
| Token | Matches | Example |
|---|---|---|
* | exactly one level | orders.* matches orders.created, not orders.us-east.created |
> | one or more levels | orders.> matches orders.created and orders.us-east.created |
A standalone > subscribes to everything — a firehose for audit or debugging.
One pattern subscription captures many channels: orders.* matches single-level order events, while > captures everything.
Pitfall: wildcards belong to subscriptions, not publishes. A publisher must always send to a concrete channel name — orders.created, never orders.*. The * and > characters are illegal in a publish channel.
Routing — one publish, many channels
Wildcards let one subscriber listen to many channels. Multicast routing is the mirror image: it lets one publish reach many channels at once, without the publisher looping or opening multiple connections.
The publisher encodes a list of targets into the channel name, and the broker fans the message out to each. This is how you tee a single business event to several consumers with different needs — a live feed and a durable copy and a work queue — from one call.
A single publish fans out to channels of different types at once — a real-time feed, a durable store, and a reliable work queue.
Precise definition
- Channel — a named destination string. Created on first use, addressed by publishers and subscribers; the unit the broker routes on.
- Hierarchical naming — a dot-separated convention (
domain.entity.action) that gives channels structure so patterns can match levels. - Wildcard subscription — a subscription whose channel is a pattern using
*(one level) or>(one or more levels). The broker delivers every message whose channel matches. - Multicast routing — a single publish addressed to multiple channels at once, encoded in the channel string; the broker delivers a copy to each target.
Trade-offs
| When it helps | When it bites |
|---|---|
A consumer needs a whole category of channels — one orders.> beats a dozen explicit subscriptions. | A too-broad pattern (>) hauls in traffic you do not need, wasting bandwidth and processing. |
| You want to tee one event to several patterns (live + durable + queue) without publisher-side loops. | Routing to many targets multiplies broker work per publish; very wide fan-outs add latency. |
| A naming hierarchy lets new channels appear without changing subscribers. | Inconsistent naming breaks wildcards — order.created and orders.created will not match the same pattern. |
| Routing keeps publishers simple — they do not track who consumes what. | Routing hides destinations in a string; an inspectable, documented naming scheme is essential to avoid surprise delivery. |
In KubeMQ
KubeMQ channels are exactly the named destinations above — a plain string you choose, created on first use. Wildcard subscriptions are supported for Events (Pub/Sub): subscribe to orders.* or > and the broker matches every event channel against your pattern. Multicast routing is encoded directly in the channel string: ; separates targets and a type: prefix selects the pattern.
| Routing string | Effect |
|---|---|
events:order-live;events_store:order-archive | one publish → a live feed and a durable copy |
events:notify;queues:order-fulfilment | broadcast and a reliable work queue |
The snippet below is the canonical wildcard subscribe from the Events tutorial — one subscription to orders.* captures every single-level order channel.
sub, err := client.SubscribeToEvents(ctx, "orders.*", "",
kubemq.WithOnEvent(func(event *kubemq.Event) {
fmt.Printf("[Orders Monitor] channel=%s body=%s\n",
event.Channel, string(event.Body))
}),
kubemq.WithOnError(func(err error) {
log.Println("Error:", err)
}),
)client.subscribe_to_events(
subscription=EventsSubscription(
channel="orders.*",
on_receive_event_callback=lambda e: print(
f"[Orders Monitor] channel={e.channel} body={e.body.decode()}"
),
on_error_callback=lambda e: print(f"Error: {e}"),
),
cancel=CancellationToken(),
)client.subscribeToEvents({
channel: "orders.*",
onEvent: (msg) =>
console.log(
`[Orders Monitor] channel=${msg.channel} body=${Buffer.from(msg.body).toString()}`
),
onError: (err) => console.error("Error:", err.message),
});client.subscribeToEvents(EventsSubscription.builder()
.channel("orders.*")
.onReceiveEventCallback(event ->
System.out.printf("[Orders Monitor] channel=%s body=%s%n",
event.getChannel(), new String(event.getBody())))
.onErrorCallback(err ->
System.err.println("Error: " + err.getMessage()))
.build());await foreach (var msg in client.SubscribeToEventsAsync(
new EventsSubscription { Channel = "orders.*" }))
{
Console.WriteLine($"[Orders Monitor] channel={msg.Channel} "
+ $"body={Encoding.UTF8.GetString(msg.Body.Span)}");
}client.subscribeToEvents(
channel = "orders.*",
onEvent = { event ->
println("[Orders Monitor] channel=${event.channel} body=${String(event.body)}")
},
onError = { err -> System.err.println("Error: ${err.message}") }
)client.subscribeToEvents("orders.*", "",
[](const kubemq::Event& event) {
std::cout << "[Orders Monitor] channel=" << event.channel
<< " body=" << event.body << std::endl;
},
[](const std::string& err) {
std::cerr << "Error: " << err << std::endl;
}
);// A single wildcard subscription matches every channel under the pattern.
let sub = client
.subscribe_to_events(
"orders.*",
"",
|event| {
Box::pin(async move {
println!(
"[Orders Monitor] channel={}, body={}",
event.channel,
String::from_utf8_lossy(&event.body)
);
})
},
None,
)
.await?;cancel = KubeMQ::CancellationToken.new
sub = KubeMQ::PubSub::EventsSubscription.new(channel: "orders.*")
client.subscribe_to_events(sub, cancellation_token: cancel,
on_error: ->(e) { puts "Error: #{e.message}" }) do |event|
puts "[Orders Monitor] channel=#{event.channel} body=#{event.body}"
end{:ok, sub} =
KubeMQ.Client.subscribe_to_events(client, "orders.*",
on_event: fn event ->
IO.puts("[Orders Monitor] channel=#{event.channel} body=#{event.body}")
end
)In KubeMQ: wildcard subscriptions are an Events feature. Events Store, Queues, and RPC use exact channel names — they do not match * or > patterns. Multicast routing, by contrast, works across patterns: one routing string can tee an event into Events, Events Store, and Queues at the same time.
How KubeMQ does this →
Channel Routing
The hands-on guide to multicast routing syntax — publish once to many channels and patterns.
Channel Management
Inspect, list, and manage channels across patterns.
Wildcard Subscriptions
Step-by-step: subscribe to orders.* and > with the Events SDK.
Multicast Events
Fan one publish out to multiple channels from a single call.
Events — Real-Time Pub/Sub
The pattern where channels and wildcards live.
Was this page helpful?