Skip to content

AspNetCore.Kafka - a simple Kafka client and messaging infrastructure for ASP .Net Core.

License

Notifications You must be signed in to change notification settings

VladislavRybnikov/aspnetcorekafka

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

70 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AspNetCore.Kafka

Sample program

The following implementation covers:

  • An abstraction over Confluent.Kafka with a predefined TPL based subscription blocks.
  • Subscribe in declarative way as well as a regular fluent style.
  • Intercept messages.
  • Buffering, batching etc.
  • An In-memory broker provider for unit and integration testing.

Registration

// Get Kafka bootstrap servers from ConnectionString:Kafka options
services.AddKafka(Configuration);

Message handlers

To cover different scenarios - subscriptions can be declared in several ways:

  • type marked with a [MessageHandler] attribute and any number of methods (subscriptions) marked with [Message] attribute.
  • type that implements IMessageHandler interface and any number of methods (subscriptions) marked with [Message] attribute.
  • type that implements [MessageHandler] interface and a [HandleAsync(T)] method (subscription) implementation. For multiple subscriptions within a single type - that type should implement multiple interfaces.

Fluent subscription

Example 1

  var subscription = _consumer.Subscribe("topic-name", x => LogAsync(x), new SubscriptionOptions { 
    Format = TopicFormat.Avro, 
    Offset = TopicOffset.Begin,
    Bias = -1000,
    DateOffset = DateTimeOffset.UtcNow - TimeSpan.FromDays(1),
    RelativeOffsetMinutes = TimeSpan.FromDays(1)
  });

Example 2

  var subscription = _consumer
    .Pipeline("topic-name", new SubscriptionOptions { ... })
    .Buffer(100)
    .Batch(100, TimeSpan.FromSeconds(5))
    .Action(x => LogAsync(x))
    .Commit()
    .Subscribe();

Message contract declaration

[Message(Topic = "event.currency.rate-{env}", Format = TopicFormat.Avro)]
public class RateNotification
{
    public string Currency { get; set; }
    public decimal Rate { get; set; }
}

Attribute based subscription

  • Subscribe all Types marked with [MessageHandler] attribute.
  • Message handler and specific subscription on a method marked with [Message] attribute.
// Kafka message handler
[MessageHandler]
public class RateNotificationMessageHandler
{
    // class with proper DI support.

    // with message wrapper
    [Message] public Task Handler(IMessage<RateNotification> message) { ... };
    
    // or handle payload directly
    [Message] public Task Handler(RateNotification message) { ... };
}

Subscription over an interface

  • Subscribe all Types implementing [IMessageHandler] interface.
  • Message handler and specific subscription on a method marked with [Message] attribute.
// Kafka message handler
public class RateNotificationMessageHandler : IMessageHandler
{
    // class with proper DI support.

    // with message wrapper
    [Message] public Task Handler(IMessage<RateNotification> message) { ... }
    
    // or handle payload directly
    [Message] public Task Handler(RateNotification message) { ... };
}

Subscription over an interface with specific message type

  • Subscribe all Types implementing [IMessageHandler] interface.
  • Message handler and specific subscription on a [Handle] method that implements IMessageHandler.
// with message wrapper
public class RateNotificationMessageHandler : IMessageHandler<IMessage<RateNotification>>
{
    // class with proper DI support.

    public Task HandleAsync(IMessage<RateNotification> message) { ... }
}

// or handle payload directly
public class RateNotificationMessageHandler : IMessageHandler<RateNotification>
{
    // class with proper DI support.

    public Task HandleAsync(RateNotification message) { ... }
}

In-place topic details

// Kafka message handler
public class WithdrawNotificationMessageHandler : IMessageHandler
{
    // class with proper DI support.

    // Inplace topic subscription definition and a backing consumption buffer
    [Message(Topic = "withdraw_event-{env}", Format = TopicFormat.Avro, Offset = TopicOffset.Begin))]
    public Task Handler(IMessage<WithdrawNotification> message)
    {
        Console.WriteLine($"Withdraw {message.Value.Amount} {message.Value.Currency}");
        return Task.CompletedTask;
    }
}

Message blocks

Batches and/or Buffer and Commit

[MessageHandler]
public class RateNotificationHandler
{
    // required
    [Message]
    // buffer messages
    [Buffer(Size = 100)]
    // use constant values
    [Batch(Size = 190, Time = 5000)]
    //commit after handler finished
    [Commit]
    // Parameter of type IEnumerable<IMessage<RateNotification>> is also supported
    public Task Handler(IMessageEnumerable<RateNotification> messages)
    {
        Console.WriteLine($"Received batch with size {messages.Count}");
        return Task.CompletedTask;
    }
}

Interceptors

public class MyInterceptor : IMessageInterceptor
{
    public Task ConsumeAsync(IMessage<object> message, Exception exception);
    {
        Console.WriteLine($"{message.Topic} processed. Exception: {exception}");
        return Task.CompletedTask;
    }
    
    public Task ProduceAsync(string topic, object key, object message, Exception exception)
    {
        Console.WriteLine($"{message.Topic} produced. Exception: {exception}");
        return Task.CompletedTask;
    }
}

services
    .AddKafka(Configuration)
    .AddInterceptor(new MyInterceptor())
    // or
    .AddInterceptor(x => new MyInterceptor())
    // or
    .AddInterceptor(typeof(MyInterceptor))
    // or
    .AddInterceptor<MyInterceptor>();

In-memory broker for Consumer/Producer mocking

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddKafka(_config)
        .UseInMemoryBroker();
}

Metrics

Implemented as a MetricsInterceptor.

services
    .AddKafka(Configuration)
    .AddMetrics();

Configuration

{
  "Kafka": {
    "Group": "consumer-group-name",
    "Producer": {
      "linger.ms": 5,
      "socket.timeout.ms": 15000,
      "message.send.max.retries": 10,
      "message.timeout.ms": 200000
    },
    "Consumer": {
      "socket.timeout.ms": 15000,
      "enable.auto.commit": false
    }
  },
  "ConnectionStrings": {
    "Kafka": "192.168.0.1:9092,192.168.0.2:9092",
    "SchemaRegistry": "http://192.168.0.1:8084"
  }
}

About

AspNetCore.Kafka - a simple Kafka client and messaging infrastructure for ASP .Net Core.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%