public void KafkaReceiverConstructor2HappyPath() { var name = "name"; var topic = "topic"; var groupId = "groupId"; var servers = "bootstrapServers"; var enableOffsetRestore = true; var autoOffsetReset = AutoOffsetReset.Error; var consumer = new ConsumerConfig() { GroupId = groupId, BootstrapServers = servers, EnableAutoOffsetStore = enableOffsetRestore, AutoOffsetReset = autoOffsetReset }; var receiver = new KafkaReceiver(name, topic, consumer); receiver.Name.Should().Be(name); receiver.Topic.Should().Be(topic); receiver.GroupId.Should().Be(groupId); receiver.BootstrapServers.Should().Be(servers); receiver.EnableAutoOffsetStore.Should().Be(enableOffsetRestore); receiver.AutoOffsetReset.Should().Be(autoOffsetReset); receiver.Consumer.Should().NotBeNull(); }
public static void CreateWithSchemaIdRequired() { var name = "name"; var topic = "topic"; var groupId = "groupId"; var servers = "bootstrapServers"; var enableOffsetRestore = true; var schemaIdRequired = true; var autoOffsetReset = AutoOffsetReset.Error; var consumer = new ConsumerConfig() { GroupId = groupId, BootstrapServers = servers, EnableAutoOffsetStore = enableOffsetRestore, AutoOffsetReset = autoOffsetReset }; using var receiver = new KafkaReceiver(name, topic, consumer, schemaIdRequired: schemaIdRequired); receiver.Name.Should().Be(name); receiver.Topic.Should().Be(topic); receiver.GroupId.Should().Be(groupId); receiver.BootstrapServers.Should().Be(servers); receiver.EnableAutoOffsetStore.Should().Be(enableOffsetRestore); receiver.AutoOffsetReset.Should().Be(autoOffsetReset); receiver.Consumer.Should().NotBeNull(); var unlockedReceiver = receiver.Unlock(); Assert.Equal(schemaIdRequired, unlockedReceiver._schemaIdRequired); }
public static void CallAddStatisticsEmittedHandlerForReceiverWithNull() { using var receiver = new KafkaReceiver("NAME", "TOPIC", "GROUPID", "SERVERS"); Action action = () => receiver.AddStatisticsEmittedHandler(null !); action.Should().Throw <ArgumentNullException>(); }
public void SeekMethodSadPath() { var receiver = new KafkaReceiver("name", "one_topic", "groupId", "servers"); Action act = () => receiver.Seek(DateTime.Now); act.Should().ThrowExactly <InvalidOperationException>() .WithMessage("Seek cannot be called before the receiver has been started."); }
public void KafkaReceiverConstructor1HappyPath() { var name = "name"; var topic = "topic"; var groupId = "groupId"; var servers = "bootstrapServers"; var sender = new KafkaReceiver(name, topic, groupId, servers); sender.Name.Should().Be(name); sender.Topic.Should().Be(topic); sender.Consumer.Should().NotBeNull(); }
public void SeekMethodHappyPath() { var assignments = new List <TopicPartition> { new TopicPartition("one_topic", new Partition(0)), new TopicPartition("one_topic", new Partition(1)) }; var offsetsForTimes = new List <TopicPartitionOffset> { new TopicPartitionOffset(assignments[0], new Offset(1)), new TopicPartitionOffset(assignments[1], new Offset(2)) }; TopicPartitionTimestamp[] actualTimestamps = null; Action <IEnumerable <TopicPartitionTimestamp>, TimeSpan> callback = (timestamps, timeout) => actualTimestamps = timestamps.ToArray(); var mockConsumer = new Mock <IConsumer <string, byte[]> >(); mockConsumer.Setup(m => m.Assignment).Returns(assignments); mockConsumer.Setup(m => m.OffsetsForTimes(It.IsAny <IEnumerable <TopicPartitionTimestamp> >(), It.IsAny <TimeSpan>())) .Returns(offsetsForTimes) .Callback(callback); var lazyConsumer = new Lazy <IConsumer <string, byte[]> >(() => mockConsumer.Object); var receiver = new KafkaReceiver("name", "one_topic", "groupId", "servers"); receiver.Unlock()._consumer = lazyConsumer; var timestamp = new DateTime(2020, 9, 3, 17, 52, 37, DateTimeKind.Local).ToUniversalTime(); receiver.Seek(timestamp); mockConsumer.Verify(m => m.Seek(offsetsForTimes[0]), Times.Once()); mockConsumer.Verify(m => m.Seek(offsetsForTimes[1]), Times.Once()); var expectedTimestampsToSearch = assignments.Select(tp => new TopicPartitionTimestamp(tp, new Timestamp(timestamp))).ToArray(); mockConsumer.Verify(m => m.OffsetsForTimes(expectedTimestampsToSearch, It.IsAny <TimeSpan>()), Times.Once()); actualTimestamps.Should().HaveCount(2); actualTimestamps.Select(t => t.TopicPartition).Should().BeEquivalentTo(assignments); actualTimestamps.Select(t => t.Timestamp.UtcDateTime).Should().AllBeEquivalentTo(timestamp); }
public void KafkaReceiverStartHappyPath1() { var receiver = new KafkaReceiver("name", "one_topic", "groupId", "servers"); var consumerMock = new Mock <IConsumer <string, byte[]> >(); consumerMock.Setup(c => c.Subscribe(It.IsAny <string>())); var unlockedReceiver = receiver.Unlock(); unlockedReceiver._consumer = new Lazy <IConsumer <string, byte[]> >(() => consumerMock.Object); unlockedReceiver.Start(); consumerMock.Verify(cm => cm.Subscribe("one_topic"), Times.Once); unlockedReceiver.Dispose(); }
public static void CallAddStatisticsEmittedHandlerForReceiver() { using var receiver = new KafkaReceiver("NAME", "TOPIC", "GROUPID", "SERVERS"); var statsData = "STATS!"; var callCount = 0; void Handler(object?sender, string stats) { sender.Should().BeSameAs(receiver); stats.Should().Be(statsData); callCount++; } receiver.AddStatisticsEmittedHandler(Handler); receiver.Unlock().OnStatisticsEmitted(null, statsData); callCount.Should().Be(1, "Event handler should have been called"); }
public async Task ReplayMethodHappyPath2() { Func <IReceiverMessage, Task> capturedCallback = null; Action <DateTime, DateTime?, Func <IReceiverMessage, Task>, string, string, bool, AutoOffsetReset> mockReplayEngineCallback = (start, end, callback, topic, bootstrapServers, enableAutoOffsetStore, autoOffsetReset) => { capturedCallback = callback; }; var mockReplayEngine = new Mock <IReplayEngine>(); mockReplayEngine.Setup(m => m.Replay(It.IsAny <DateTime>(), It.IsAny <DateTime?>(), It.IsAny <Func <IReceiverMessage, Task> >(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <AutoOffsetReset>())) .Returns(Task.CompletedTask) .Callback(mockReplayEngineCallback); var mockMessageHandler = new Mock <IMessageHandler>(); mockMessageHandler.Setup(m => m.OnMessageReceivedAsync(It.IsAny <IReceiver>(), It.IsAny <IReceiverMessage>())) .Returns(Task.CompletedTask); var receiver = new KafkaReceiver("name", "one_topic", "groupId", "servers", true, AutoOffsetReset.Earliest, mockReplayEngine.Object); receiver.MessageHandler = mockMessageHandler.Object; var expectedStart = new DateTime(2020, 9, 3, 20, 22, 58, DateTimeKind.Local).ToUniversalTime(); var expectedEnd = new DateTime(2020, 9, 3, 20, 23, 19, DateTimeKind.Local).ToUniversalTime(); await receiver.Replay(expectedStart, expectedEnd, null); mockReplayEngine.Verify(m => m.Replay(expectedStart, expectedEnd, It.IsAny <Func <IReceiverMessage, Task> >(), "one_topic", "servers", true, AutoOffsetReset.Earliest), Times.Once()); capturedCallback.Should().NotBeNull(); var message = new FakeReceiverMessage("Hello, world!"); await capturedCallback(message); mockMessageHandler.Verify(m => m.OnMessageReceivedAsync(receiver, message), Times.Once()); }
public static void Create() { var name = "name"; var topic = "topic"; var groupId = "groupId"; var servers = "bootstrapServers"; var enableOffsetRestore = true; var autoOffsetReset = AutoOffsetReset.Error; using var receiver = new KafkaReceiver(name, topic, groupId, servers, enableOffsetRestore, autoOffsetReset); receiver.Name.Should().Be(name); receiver.Topic.Should().Be(topic); receiver.GroupId.Should().Be(groupId); receiver.BootstrapServers.Should().Be(servers); receiver.EnableAutoOffsetStore.Should().Be(enableOffsetRestore); receiver.AutoOffsetReset.Should().Be(autoOffsetReset); receiver.Consumer.Should().NotBeNull(); }
public static void KafkaReceiverStopWithDispose() { using var receiver = new KafkaReceiver("name", "one_topic", "groupId", "servers"); var consumerMock = new Mock <IConsumer <string, byte[]> >(); consumerMock.Setup(cm => cm.Close()); consumerMock.Setup(cm => cm.Dispose()); var unlockedReceiver = receiver.Unlock(); unlockedReceiver._consumer = new Lazy <IConsumer <string, byte[]> >(() => consumerMock.Object); unlockedReceiver.Start(); unlockedReceiver.Dispose(); consumerMock.Verify(cm => cm.Close(), Times.Once); consumerMock.Verify(cm => cm.Dispose(), Times.Once); }
public async Task ReplayMethodHappyPath1() { var mockReplayEngine = new Mock <IReplayEngine>(); mockReplayEngine.Setup(m => m.Replay(It.IsAny <DateTime>(), It.IsAny <DateTime?>(), It.IsAny <Func <IReceiverMessage, Task> >(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <AutoOffsetReset>())) .Returns(Task.CompletedTask); var receiver = new KafkaReceiver("name", "one_topic", "groupId", "servers", true, AutoOffsetReset.Earliest, mockReplayEngine.Object); var start = new DateTime(2020, 9, 3, 20, 22, 58, DateTimeKind.Local).ToUniversalTime(); var end = new DateTime(2020, 9, 3, 20, 23, 19, DateTimeKind.Local).ToUniversalTime(); Func <IReceiverMessage, Task> callback = message => Task.CompletedTask; await receiver.Replay(start, end, callback); mockReplayEngine.Verify(m => m.Replay(start, end, callback, "one_topic", "servers", true, AutoOffsetReset.Earliest), Times.Once()); }
public void KafkaReceiverHappyPath() { var message = new Message <string, byte[]>() { Value = Encoding.UTF8.GetBytes("This is the expected message!") }; var result = new ConsumeResult <string, byte[]>() { Message = message }; var consumerMock = new Mock <IConsumer <string, byte[]> >(); consumerMock.Setup(c => c.Subscribe(It.IsAny <string>())); consumerMock.Setup(c => c.Consume(It.IsAny <CancellationToken>())).Returns(result); var waitHandle = new AutoResetEvent(false); string receivedMessage = null; using (var receiver = new KafkaReceiver("NAME", "TOPIC", "GROUPID", "SERVER")) { var unlockedReceiver = receiver.Unlock(); unlockedReceiver._consumer = new Lazy <IConsumer <string, byte[]> >(() => consumerMock.Object); receiver.Start(m => { receivedMessage = m.StringPayload; waitHandle.Set(); return(Task.CompletedTask); }); waitHandle.WaitOne(); } consumerMock.Verify(m => m.Consume(It.IsAny <CancellationToken>())); receivedMessage.Should().Be("This is the expected message!"); }
public async Task ReplayMethodSadPath() { var mockReplayEngine = new Mock <IReplayEngine>(); mockReplayEngine.Setup(m => m.Replay(It.IsAny <DateTime>(), It.IsAny <DateTime?>(), It.IsAny <Func <IReceiverMessage, Task> >(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <AutoOffsetReset>())) .Returns(Task.CompletedTask); var receiver = new KafkaReceiver("name", "one_topic", "groupId", "servers", true, AutoOffsetReset.Earliest, mockReplayEngine.Object); var start = new DateTime(2020, 9, 3, 20, 22, 58, DateTimeKind.Local).ToUniversalTime(); var end = new DateTime(2020, 9, 3, 20, 23, 19, DateTimeKind.Local).ToUniversalTime(); Func <Task> act = async() => await receiver.Replay(start, end, null); (await act.Should().ThrowExactlyAsync <InvalidOperationException>()) .WithMessage("Replay cannot be called with a null 'callback' parameter before the receiver has been started."); mockReplayEngine.Verify(m => m.Replay(It.IsAny <DateTime>(), It.IsAny <DateTime?>(), It.IsAny <Func <IReceiverMessage, Task> >(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <AutoOffsetReset>()), Times.Never()); }
private void TestMessageBrokerReceivers() { IMessageReceiver <FileUploadedEvent> fileUploadedMessageQueueReceiver = null; IMessageReceiver <FileDeletedEvent> fileDeletedMessageQueueReceiver = null; if (AppSettings.MessageBroker.UsedRabbitMQ()) { fileUploadedMessageQueueReceiver = new RabbitMQReceiver <FileUploadedEvent>(new RabbitMQReceiverOptions { HostName = AppSettings.MessageBroker.RabbitMQ.HostName, UserName = AppSettings.MessageBroker.RabbitMQ.UserName, Password = AppSettings.MessageBroker.RabbitMQ.Password, QueueName = AppSettings.MessageBroker.RabbitMQ.QueueName_FileUploaded, }); fileDeletedMessageQueueReceiver = new RabbitMQReceiver <FileDeletedEvent>(new RabbitMQReceiverOptions { HostName = AppSettings.MessageBroker.RabbitMQ.HostName, UserName = AppSettings.MessageBroker.RabbitMQ.UserName, Password = AppSettings.MessageBroker.RabbitMQ.Password, QueueName = AppSettings.MessageBroker.RabbitMQ.QueueName_FileDeleted, }); } if (AppSettings.MessageBroker.UsedKafka()) { fileUploadedMessageQueueReceiver = new KafkaReceiver <FileUploadedEvent>( AppSettings.MessageBroker.Kafka.BootstrapServers, AppSettings.MessageBroker.Kafka.Topic_FileUploaded, AppSettings.MessageBroker.Kafka.GroupId); fileDeletedMessageQueueReceiver = new KafkaReceiver <FileDeletedEvent>( AppSettings.MessageBroker.Kafka.BootstrapServers, AppSettings.MessageBroker.Kafka.Topic_FileDeleted, AppSettings.MessageBroker.Kafka.GroupId); } if (AppSettings.MessageBroker.UsedAzureQueue()) { fileUploadedMessageQueueReceiver = new AzureQueueReceiver <FileUploadedEvent>( AppSettings.MessageBroker.AzureQueue.ConnectionString, AppSettings.MessageBroker.AzureQueue.QueueName_FileUploaded); fileDeletedMessageQueueReceiver = new AzureQueueReceiver <FileDeletedEvent>( AppSettings.MessageBroker.AzureQueue.ConnectionString, AppSettings.MessageBroker.AzureQueue.QueueName_FileDeleted); } if (AppSettings.MessageBroker.UsedAzureServiceBus()) { fileUploadedMessageQueueReceiver = new AzureServiceBusReceiver <FileUploadedEvent>( AppSettings.MessageBroker.AzureServiceBus.ConnectionString, AppSettings.MessageBroker.AzureServiceBus.QueueName_FileUploaded); fileDeletedMessageQueueReceiver = new AzureServiceBusReceiver <FileDeletedEvent>( AppSettings.MessageBroker.AzureServiceBus.ConnectionString, AppSettings.MessageBroker.AzureServiceBus.QueueName_FileDeleted); } var connection = new HubConnectionBuilder() .WithUrl($"{AppSettings.NotificationServer.Endpoint}/SimulatedLongRunningTaskHub") .AddMessagePackProtocol() .Build(); fileUploadedMessageQueueReceiver?.Receive(data => { Thread.Sleep(5000); // simulate long running task string message = data.FileEntry.Id.ToString(); connection.StartAsync().GetAwaiter().GetResult(); connection.InvokeAsync("SendTaskStatus", $"{AppSettings.MessageBroker.Provider} - File Uploaded", message); connection.StopAsync().GetAwaiter().GetResult(); }); fileDeletedMessageQueueReceiver?.Receive(data => { Thread.Sleep(5000); // simulate long running task string message = data.FileEntry.Id.ToString(); connection.StartAsync().GetAwaiter().GetResult(); connection.InvokeAsync("SendTaskStatus", $"{AppSettings.MessageBroker.Provider} - File Deleted", message); connection.StopAsync().GetAwaiter().GetResult(); }); }
private void RunMessageBrokerReceivers() { IMessageReceiver <FileUploadedEvent> fileUploadedMessageQueueReceiver = null; IMessageReceiver <FileDeletedEvent> fileDeletedMessageQueueReceiver = null; if (AppSettings.MessageBroker.UsedRabbitMQ()) { fileUploadedMessageQueueReceiver = new RabbitMQReceiver <FileUploadedEvent>(new RabbitMQReceiverOptions { HostName = AppSettings.MessageBroker.RabbitMQ.HostName, UserName = AppSettings.MessageBroker.RabbitMQ.UserName, Password = AppSettings.MessageBroker.RabbitMQ.Password, QueueName = AppSettings.MessageBroker.RabbitMQ.QueueName_FileUploaded, AutomaticCreateEnabled = true, ExchangeName = AppSettings.MessageBroker.RabbitMQ.ExchangeName, RoutingKey = AppSettings.MessageBroker.RabbitMQ.RoutingKey_FileUploaded, }); fileDeletedMessageQueueReceiver = new RabbitMQReceiver <FileDeletedEvent>(new RabbitMQReceiverOptions { HostName = AppSettings.MessageBroker.RabbitMQ.HostName, UserName = AppSettings.MessageBroker.RabbitMQ.UserName, Password = AppSettings.MessageBroker.RabbitMQ.Password, QueueName = AppSettings.MessageBroker.RabbitMQ.QueueName_FileDeleted, AutomaticCreateEnabled = true, ExchangeName = AppSettings.MessageBroker.RabbitMQ.ExchangeName, RoutingKey = AppSettings.MessageBroker.RabbitMQ.RoutingKey_FileDeleted, }); } if (AppSettings.MessageBroker.UsedKafka()) { fileUploadedMessageQueueReceiver = new KafkaReceiver <FileUploadedEvent>( AppSettings.MessageBroker.Kafka.BootstrapServers, AppSettings.MessageBroker.Kafka.Topic_FileUploaded, AppSettings.MessageBroker.Kafka.GroupId); fileDeletedMessageQueueReceiver = new KafkaReceiver <FileDeletedEvent>( AppSettings.MessageBroker.Kafka.BootstrapServers, AppSettings.MessageBroker.Kafka.Topic_FileDeleted, AppSettings.MessageBroker.Kafka.GroupId); } if (AppSettings.MessageBroker.UsedAzureQueue()) { fileUploadedMessageQueueReceiver = new AzureQueueReceiver <FileUploadedEvent>( AppSettings.MessageBroker.AzureQueue.ConnectionString, AppSettings.MessageBroker.AzureQueue.QueueName_FileUploaded); fileDeletedMessageQueueReceiver = new AzureQueueReceiver <FileDeletedEvent>( AppSettings.MessageBroker.AzureQueue.ConnectionString, AppSettings.MessageBroker.AzureQueue.QueueName_FileDeleted); } if (AppSettings.MessageBroker.UsedAzureServiceBus()) { fileUploadedMessageQueueReceiver = new AzureServiceBusReceiver <FileUploadedEvent>( AppSettings.MessageBroker.AzureServiceBus.ConnectionString, AppSettings.MessageBroker.AzureServiceBus.QueueName_FileUploaded); fileDeletedMessageQueueReceiver = new AzureServiceBusReceiver <FileDeletedEvent>( AppSettings.MessageBroker.AzureServiceBus.ConnectionString, AppSettings.MessageBroker.AzureServiceBus.QueueName_FileDeleted); } var notification = new SignalRNotification(); var endpoint = $"{AppSettings.NotificationServer.Endpoint}/SimulatedLongRunningTaskHub"; fileUploadedMessageQueueReceiver?.Receive(data => { Thread.Sleep(5000); // simulate long running task string message = data.FileEntry.Id.ToString(); notification.Send(endpoint, "SendTaskStatus", new { Step = $"{AppSettings.MessageBroker.Provider} - File Uploaded", Message = message }); }); fileDeletedMessageQueueReceiver?.Receive(data => { Thread.Sleep(5000); // simulate long running task string message = data.FileEntry.Id.ToString(); notification.Send(endpoint, "SendTaskStatus", new { Step = $"{AppSettings.MessageBroker.Provider} - File Deleted", Message = message }); }); }
public BatchingKafkaReceiverTelemetryDecorator(KafkaReceiver receiver) { _receiver = receiver; }
private static void Main(string[] args) { var connection = new HubConnectionBuilder() .WithUrl("http://localhost:62710/SimulatedLongRunningTaskHub") .AddMessagePackProtocol() .Build(); connection.On <string>("ReceiveTaskStatus", (message) => { Console.WriteLine(message); }); connection.StartAsync().GetAwaiter().GetResult(); var rabbitMQFileUploadedEventReceiver = new RabbitMQReceiver <FileUploadedEvent>(new RabbitMQReceiverOptions { HostName = "localhost", UserName = "******", Password = "******", QueueName = "classifiedadds_fileuploaded", }); rabbitMQFileUploadedEventReceiver.Receive(data => { Console.WriteLine("RabbitMQ - File Uploaded: " + data.FileEntry.Id); }); var rabbitMQFileDeletedEventReceiver = new RabbitMQReceiver <FileDeletedEvent>(new RabbitMQReceiverOptions { HostName = "localhost", UserName = "******", Password = "******", QueueName = "classifiedadds_filedeleted", }); rabbitMQFileDeletedEventReceiver.Receive(data => { Console.WriteLine("RabbitMQ - File Deleted: " + data.FileEntry.Id); }); var kafkaFileUploadedEventReceiver = new KafkaReceiver <FileUploadedEvent>("localhost:9092", "classifiedadds_fileuploaded", "classified"); kafkaFileUploadedEventReceiver.Receive(data => { Console.WriteLine("Kafka - File Uploaded: " + data.FileEntry.Id); }); var kafkaFileDeletedEventReceiver = new KafkaReceiver <FileDeletedEvent>("localhost:9092", "classifiedadds_filedeleted", "classified"); kafkaFileDeletedEventReceiver.Receive(data => { Console.WriteLine("Kafka - File Deleted: " + data.FileEntry.Id); }); var azureQueueFileUploadedEventReceiver = new AzureQueueReceiver <FileUploadedEvent>("DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx;EndpointSuffix=core.windows.net", "classifiedadds-fileuploaded"); azureQueueFileUploadedEventReceiver.Receive(data => { Console.WriteLine("AzureQueue - File Uploaded:" + data.FileEntry.Id); }); var azureQueueFileDeletedEventReceiver = new AzureQueueReceiver <FileDeletedEvent>("DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx;EndpointSuffix=core.windows.net", "classifiedadds-filedeleted"); azureQueueFileDeletedEventReceiver.Receive(data => { Console.WriteLine("AzureQueue - File Deleted:" + data.FileEntry.Id); }); var azureServiceBusFileUploadedEventReceiver = new AzureServiceBusReceiver <FileUploadedEvent>("Endpoint=sb://xxx.servicebus.windows.net/;SharedAccessKeyName=xxx;SharedAccessKey=xxx", "classifiedadds_fileuploaded"); azureServiceBusFileUploadedEventReceiver.Receive(data => { Console.WriteLine("AzureServiceBus - File Uploaded:" + data.FileEntry.Id); }); var azureServiceBusFileDeletedEventReceiver = new AzureServiceBusReceiver <FileDeletedEvent>("Endpoint=sb://xxx.servicebus.windows.net/;SharedAccessKeyName=xxx;SharedAccessKey=xxx", "classifiedadds_filedeleted"); azureServiceBusFileDeletedEventReceiver.Receive(data => { Console.WriteLine("AzureServiceBus - File Deleted:" + data.FileEntry.Id); }); Console.WriteLine("Listening..."); Console.ReadLine(); rabbitMQFileUploadedEventReceiver.Dispose(); rabbitMQFileDeletedEventReceiver.Dispose(); }
public BatchingKafkaReceiverTelemetryDecorator(KafkaReceiver receiver, TReceiverActionReporter publisher) { _receiver = receiver; _publisher = publisher; }