Samples
Code examples for Surgewave.
.NET Examples
Simple Producer
using Kuestenlogik.Surgewave.Client.Native;
await using var client = new SurgewaveNativeClient("localhost", 9092);
await client.ConnectAsync();
// Single message
await client.Messaging.Send("orders")
.WithKey("order-123")
.WithValue("New order")
.ExecuteAsync();
// Batch
await client.Messaging.Send("orders")
.WithKey("order-1").WithValue(data1)
.And("order-2", data2)
.SendAllAsync();
Simple Consumer
await using var consumer = new SurgewaveConsumer<string, string>(options =>
{
options.BootstrapServers = "localhost:9092";
});
consumer.Subscribe("orders");
while (true)
{
var message = await consumer.ConsumeAsync();
if (message != null)
Console.WriteLine($"Key: {message.Key}, Value: {message.Value}");
}
Typed Producer/Consumer
// Producer
await using var producer = new SurgewaveProducer<string, Order>(options =>
{
options.BootstrapServers = "localhost:9092";
options.ValueSerializer = Serializers.Json<Order>();
});
await producer.ProduceAsync("orders", "order-123", new Order
{
Id = 123,
Customer = "Alice",
Total = 99.99m
});
// Consumer
await using var consumer = new SurgewaveConsumer<string, Order>(options =>
{
options.BootstrapServers = "localhost:9092";
options.GroupId = "order-processor";
});
consumer.Subscribe("orders");
while (true)
{
var record = await consumer.ConsumeAsync();
if (record != null)
Console.WriteLine($"Order {record.Value.Id}: ${record.Value.Total}");
}
Confluent.Kafka Compatible
using Confluent.Kafka;
// Same code works with Surgewave
var config = new ProducerConfig { BootstrapServers = "localhost:9092" };
using var producer = new ProducerBuilder<string, string>(config).Build();
await producer.ProduceAsync("my-topic", new Message<string, string>
{
Key = "key",
Value = "value"
});
Python Examples (gRPC)
Producer
import grpc
import surgewave_pb2
import surgewave_pb2_grpc
channel = grpc.insecure_channel('localhost:9093')
stub = surgewave_pb2_grpc.ProducerServiceStub(channel)
response = stub.Produce(surgewave_pb2.ProduceRequest(
topic='my-topic',
key=b'key',
value=b'value'
))
print(f'Offset: {response.offset}')
Consumer
stub = surgewave_pb2_grpc.ConsumerServiceStub(channel)
for message in stub.Consume(surgewave_pb2.ConsumeRequest(
topic='my-topic',
partition=0,
offset=0
)):
print(f'{message.key}: {message.value}')
Common Patterns
Fire and Forget
// No await, returns immediately
_ = client.Messaging.Send("events")
.WithValue(eventData)
.ExecuteAsync();
Request-Reply
var correlationId = Guid.NewGuid().ToString();
// Send request
await client.Messaging.Send("requests")
.WithKey(correlationId)
.WithValue(request)
.ExecuteAsync();
// Wait for reply using consumer
var consumer = new SurgewaveConsumer<string, byte[]>(opts =>
{
opts.BootstrapServers = "localhost:9092";
});
consumer.Subscribe("replies");
while (true)
{
var msg = await consumer.ConsumeAsync();
if (msg?.Key == correlationId)
return msg.Value;
}
Fan-Out
var topics = new[] { "service-a", "service-b", "service-c" };
await Task.WhenAll(topics.Select(topic =>
client.Messaging.Send(topic)
.WithValue(eventData)
.ExecuteAsync()));
Integration Testing
public class OrderTests : IAsyncLifetime
{
private EmbeddedSurgewave _broker;
public async Task InitializeAsync()
{
_broker = new EmbeddedSurgewave(o => o.Storage = StorageBackend.Memory);
await _broker.StartAsync();
}
public async Task DisposeAsync() => await _broker.DisposeAsync();
[Fact]
public async Task OrderCreated_PublishesEvent()
{
await using var client = new SurgewaveNativeClient("localhost", 9092);
await client.ConnectAsync();
await client.Messaging.Send("orders")
.WithValue("test")
.ExecuteAsync();
// Assert message received
}
}
Proto Files
gRPC proto files at:
src/Kuestenlogik.Surgewave.Grpc/Protos/
├── surgewave.proto
├── producer.proto
├── consumer.proto
└── admin.proto
Sample Applications
Complete sample applications in the samples/ directory:
FleetTracker
Real-time fleet tracking dashboard with 20 simulated vehicles.
samples/FleetTracker/
├── FleetTracker.Generator/ # Vehicle position simulator
├── FleetTracker.Dashboard/ # Blazor dashboard with map
└── FleetTracker.Shared/ # Shared models
Features:
- Live map with vehicle markers (Leaflet)
- Vehicle status tracking (Moving/Stopped/Idling)
- Real-time position updates at 1 Hz
Run:
dotnet run --project src/Kuestenlogik.Surgewave.Broker
dotnet run --project samples/FleetTracker/FleetTracker.Generator
dotnet run --project samples/FleetTracker/FleetTracker.Dashboard
# Open http://localhost:5000
MassFleetTracker
High-throughput stress test with 100,000 simulated vehicles.
samples/MassFleetTracker/
├── MassFleetTracker.Generator/ # 100k vehicle simulator
├── MassFleetTracker.Dashboard/ # Heatmap visualization
└── MassFleetTracker.Shared/ # Shared models
Features:
- 100,000 vehicles sending position updates
- 100,000 msg/s sustained throughput
- 100 partitions for parallel processing
- 3-tier visualization:
- Low zoom: Heatmap (vehicle density)
- Medium zoom: Cluster markers with counts
- High zoom: Individual vehicle markers
Data Volume:
| Metric | Value |
|---|---|
| Messages/second | 100,000 |
| Message size | ~150 Bytes (JSON) |
| Throughput | ~15 MB/s |
| Data/hour | ~54 GB |
Optimization Strategies:
| Strategy | Data reduction |
|---|---|
| LZ4 compression | 50-70% |
| Binary format (Protobuf) | 70% |
| Reduced frequency (5s) | 80% |
| Delta encoding | 60-80% |
Run:
dotnet run --project src/Kuestenlogik.Surgewave.Broker
dotnet run --project samples/MassFleetTracker/MassFleetTracker.Generator
dotnet run --project samples/MassFleetTracker/MassFleetTracker.Dashboard
# Open http://localhost:5000
Next Steps
- Clients - Full client documentation
- Quickstart - Getting started