.NET 10 How to implement it
| Need | Package / API | Notes |
| Producer, consumer, admin | Confluent.Kafka (2.16.x, Apache-2.0) | Wraps librdkafka. Supports idempotence, transactions, cooperative rebalancing |
| Schema registry | Confluent.SchemaRegistry.Serdes.Avro / .Protobuf / .Json | Same version line as Confluent.Kafka |
| Azure Event Hubs | Same Confluent.Kafka client | Bootstrap <namespace>.servicebus.windows.net:9093, SASL_SSL |
| Hosting | built-in BackgroundService | Consume blocks, so give the loop its own thread |
using var producer = new ProducerBuilder<string, string>(new ProducerConfig
{
BootstrapServers = servers,
Acks = Acks.All,
EnableIdempotence = true // librdkafka default is false: set it explicitly
}).Build();
await producer.ProduceAsync("payments",
new Message<string, string> { Key = accountId, Value = json }); // key = ordering scope
using var consumer = new ConsumerBuilder<string, string>(new ConsumerConfig
{
BootstrapServers = servers,
GroupId = "ledger-service",
EnableAutoCommit = false, // process, then commit = at-least-once
PartitionAssignmentStrategy = PartitionAssignmentStrategy.CooperativeSticky
}).Build();
consumer.Subscribe("payments");
while (!ct.IsCancellationRequested)
{
var r = consumer.Consume(ct);
try { await HandleIdempotentlyAsync(r.Message, ct); }
catch (Exception ex) when (ex is not OperationCanceledException)
{
await producer.ProduceAsync("payments.DLT", new Message<string, string>
{
Key = r.Message.Key, Value = r.Message.Value,
Headers = new Headers { { "error", Encoding.UTF8.GetBytes(ex.Message) } }
}, ct); // park it, don't block the partition
}
consumer.Commit(r);
}
Kafka isn't a queue. It's a log you can rewind ⏪
📜 Events are appended to partitions and kept for days, not deleted on read.
🔑 Same key, same partition, same order. Pick the key carefully (account ID, not random).
👥 A consumer group splits partitions between its members. More consumers than partitions? They sit idle.
🔁 Process, then commit. Expect duplicates and make consumers idempotent.
☠️ No built-in DLQ: park poison events in a dead-letter topic so one bad message doesn't stall a partition.
Queue for tasks, Kafka for facts many teams need to replay. Which do you reach for first?
#Kafka #EventStreaming #Integration #SolutionArchitecture