Fan-Out
Fan out messages to multiple subscribers with KubeMQ events using the C# SDK pub/sub pattern.
Overview
Fan-out is the default delivery behavior of KubeMQ Events pub/sub: when subscribers don't join a consumer group, every subscriber gets its own independent copy of each published event. Reach for it whenever several unrelated services need to react to the same occurrence — an order placed, a config change, an audit event — without the publisher knowing or caring who's listening, and without one subscriber's slowness affecting another's delivery.
The mechanism is simply omission: an EventsSubscription with no Group set puts that subscription in broadcast mode instead of load-balanced mode. SendEventAsync doesn't change at all — the publisher sends once, and the broker independently pushes a copy to every active subscriber on the channel.
Gotchas: fan-out is opt-out by default, so a typo'd or accidentally shared Group value silently turns broadcast into competing-consumer load-balancing with no error raised. Events are not persisted — a subscriber whose SubscribeToEventsAsync loop hasn't started yet when SendEventAsync runs misses that event permanently (use Events Store if you need replay). And SendEventAsync is fire-and-forget at the protocol level — it completes once the broker accepts it, not after subscribers process it — so a publisher can outrun subscription setup on a cold start, hence the delay before publishing in this sample.
Prerequisites
- KubeMQ server running on
localhost:50000 - C# SDK installed (
dotnet add package KubeMQ.SDK.CSharp)
Code
// KubeMQ .NET SDK — Patterns: Fan-Out
//
// This example demonstrates the fan-out pattern using events.
// A single publisher sends events that are received by all subscribers
// on the channel. Each subscriber independently receives every event.
//
// Prerequisites:
// - KubeMQ server running on localhost:50000
// - dotnet run
using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.Events;
using System.Text;
await using var client = new KubeMQClient(new KubeMQClientOptions
{
ClientId = "csharp-patterns-fan-out-client",
});
await client.ConnectAsync();
Console.WriteLine("Connected to KubeMQ server");
var cts = new CancellationTokenSource();
// Start 3 independent subscribers — all will receive every event (no group)
for (int n = 1; n <= 3; n++)
{
var subscriberName = $"Subscriber-{n}";
_ = Task.Run(async () =>
{
await foreach (var msg in client.SubscribeToEventsAsync(
new EventsSubscription { Channel = "csharp-patterns.fan-out" }, cts.Token))
{
Console.WriteLine($"[{subscriberName}] {Encoding.UTF8.GetString(msg.Body.Span)}");
}
});
}
// Allow subscriptions to establish
await Task.Delay(1000);
// Publish events — each subscriber receives all of them
for (var i = 1; i <= 3; i++)
{
await client.SendEventAsync(new EventMessage
{
Channel = "csharp-patterns.fan-out",
Body = Encoding.UTF8.GetBytes($"Broadcast #{i}"),
});
Console.WriteLine($"Published broadcast #{i}");
}
await Task.Delay(2000);
cts.Cancel();
Console.WriteLine("Done.");
How It Works
- All three subscribers call
SubscribeToEventsAsyncon the same channel name without aGroup— this is fan-out mode, where every subscriber receives every message independently. - Each subscription runs in its own
Task.Runloop so all three receive concurrently; thesubscriberNamevariable is captured per iteration with the loop countern. SendEventAsyncis fire-and-forget at the protocol level — the broker delivers to all active subscribers but does not wait for acknowledgements.- The 1-second delay after starting subscribers gives the gRPC streams time to register on the broker before the first event is published.
Related
Was this page helpful?