Consumer Group
Load-balance persistent events store messages across a consumer group of subscribers using the C# SDK.
Overview
A consumer group turns Events Store from a broadcast fan-out into a competing-consumers queue: subscribers sharing the same group split the stored events between them instead of each getting a copy of every event. Reach for this when a durable, ordered event log also needs to scale horizontally — a stream of order updates or audit records where one processor can't keep up, but each event still needs to be handled exactly once by the group as a whole.
It works by setting the same Group on the EventStoreSubscription passed to SubscribeToEventsStoreAsync for each subscriber, alongside a StartPosition such as EventStoreStartPosition.StartFromFirst. The broker load-balances deliveries across every active member sharing that group and channel; adding another subscriber with the same group name is all it takes to add capacity. Gotchas: the start position belongs to the group's shared read cursor, not to any one subscriber — members joining later pick up wherever the group already is, not from the beginning. Omitting Group (or using different group names) silently means broadcast instead of load balancing, with no error to warn you. Delivery is exactly-once per group, but a crashed member's in-flight event isn't automatically handed to another member — design processing to be safely restartable.
Prerequisites
- KubeMQ server running on
localhost:50000 - C# SDK installed (
dotnet add package KubeMQ.SDK.CSharp)
Code
// KubeMQ .NET SDK — Events Store: Consumer Group
//
// This example subscribes to an event store channel using a consumer group.
// Multiple instances in the same group will load-balance messages between them.
//
// Prerequisites:
// - KubeMQ server running on localhost:50000
// - dotnet run
using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.EventsStore;
using System.Text;
await using var client = new KubeMQClient(new KubeMQClientOptions
{
Address = "localhost:50000",
ClientId = "csharp-eventsstore-consumer-group-client",
});
await client.ConnectAsync();
var subscription = new EventStoreSubscription
{
Channel = "csharp-eventsstore.consumer-group",
Group = "my-consumer-group",
StartPosition = EventStoreStartPosition.StartFromFirst,
};
Console.WriteLine("Subscribed with consumer group 'my-consumer-group'. Waiting for events...");
await foreach (var evt in client.SubscribeToEventsStoreAsync(subscription))
{
Console.WriteLine($"[Seq {evt.Sequence}] {Encoding.UTF8.GetString(evt.Body.Span)}");
}
How It Works
- Setting
Group = "my-consumer-group"routes each stored event to exactly one subscriber in the group. Spin up multiple instances (differentClientId) to load-balance replay and live events across them. StartFromFirstmeans this subscriber will receive the full history of the channel from the beginning, followed by new events as they arrive.- Omitting the group switches to broadcast: every subscriber receives every stored and new event independently.
- The
await foreachwith no cancellation token runs indefinitely — terminate with Ctrl+C or pass aCancellationToken.
Related
Was this page helpful?