Stream Send
Publish persistent events at high throughput with the events store streaming API in the C# SDK.
Overview
Stream send covers publishing a batch of persistent events over one long-lived connection instead of opening a new request for each message. The single-shot SendEventStoreAsync call is fine for one-off writes, but if you're bulk-loading history, replicating a firehose of records, or backfilling an Events Store channel, paying gRPC connection overhead once instead of per-message turns network latency into your throughput ceiling instead of an app-level bottleneck.
CreateEventStoreStreamAsync opens a bidirectional gRPC stream that's reused for every send. Each stream.SendAsync(msg, clientId) still awaits the broker's acknowledgment, returning an EventStoreResult with the assigned Id and a Sent boolean confirming persistence, before CloseAsync() half-closes the write side and drains any pending confirmations. Gotchas: because each send awaits its own confirmation, this pattern is latency-bound per call — true concurrent throughput needs multiple in-flight sends, not just a shared connection; calling CloseAsync() before outstanding sends complete can cut off their confirmations; and for occasional publishing, opening and tearing down a stream is pure overhead — use SendEventStoreAsync directly instead.
Prerequisites
- KubeMQ server running on
localhost:50000 - C# SDK installed (
dotnet add package KubeMQ.SDK.CSharp)
Code
// KubeMQ .NET SDK — Events Store: Stream Publish
//
// This example demonstrates high-throughput persistent event publishing via stream.
// Each send awaits server confirmation of persistence.
//
// Prerequisites:
// - KubeMQ server running on localhost:50000
// - dotnet run
using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.EventsStore;
using System.Text;
var options = new KubeMQClientOptions
{
Address = "localhost:50000",
ClientId = "csharp-eventsstore-stream-send-client",
};
await using var client = new KubeMQClient(options);
await client.ConnectAsync();
await using var stream = await client.CreateEventStoreStreamAsync();
for (int i = 0; i < 10; i++)
{
var msg = new EventStoreMessage
{
Channel = "csharp-eventsstore.stream-send",
Body = Encoding.UTF8.GetBytes($"Persistent event #{i}"),
};
var result = await stream.SendAsync(msg, options.ClientId!);
Console.WriteLine($"Event {result.Id}: Sent={result.Sent}");
}
await stream.CloseAsync();
How It Works
CreateEventStoreStreamAsyncopens a bidirectional gRPC stream specifically for the Events Store. UnlikeSendEventStoreAsync, this reuses a single connection for all sends, reducing per-message overhead.- Each
stream.SendAsync(msg, clientId)awaits server acknowledgment of persistence before returningEventStoreResult— you get the assignedIdand aSentboolean confirming storage. CloseAsync()half-closes the write side; pending confirmations drain before the stream is torn down.- For high-throughput pipelines, this stream approach can achieve significantly higher message rates than individual
SendEventStoreAsynccalls.
Related
Was this page helpful?