public void WithHeaders_SerializationWorks() { // arrange var m = new MessageWithHeaders { Payload = _payload, Headers = { { "key1", "value1" }, { "key2", "value22" } } }; // act var payload = _serializer.Serialize(typeof(MessageWithHeaders), m); var m2 = (MessageWithHeaders)_serializer.Deserialize(typeof(MessageWithHeaders), payload); // assert m2.Headers.Count.Should().Be(2); m2.Headers.ContainsKey("key1").Should().BeTrue(); m2.Headers["key1"].ShouldBeEquivalentTo("value1"); m2.Headers.ContainsKey("key2").Should().BeTrue(); m2.Headers["key2"].ShouldBeEquivalentTo("value22"); _payload.SequenceEqual(m2.Payload).Should().BeTrue(); }
public void WhenRequestExpiredThenOnMessageExpiredIsCalled() { // arrange var onMessageExpiredMock = new Mock <Action <AbstractConsumerSettings, object> >(); var consumerSettings = new ConsumerSettings { Instances = 1, Topic = "topic1", ConsumerMode = ConsumerMode.RequestResponse, ConsumerType = typeof(IRequestHandler <SomeRequest, SomeResponse>), MessageType = typeof(SomeRequest), OnMessageExpired = onMessageExpiredMock.Object }; var p = new ConsumerInstancePool <SomeRequest>(consumerSettings, _busMock.Bus, x => Array.Empty <byte>()); var request = new SomeRequest(); var requestMessage = new MessageWithHeaders(); requestMessage.SetHeader(ReqRespMessageHeaders.Expires, _busMock.CurrentTime.AddSeconds(-10)); _busMock.BusMock.Setup(x => x.DeserializeRequest(typeof(SomeRequest), It.IsAny <byte[]>(), out requestMessage)) .Returns(request); // act p.ProcessMessage(request).Wait(); // assert _busMock.HandlerMock.Verify(x => x.OnHandle(It.IsAny <SomeRequest>(), It.IsAny <string>()), Times.Never); // the handler should not be called onMessageExpiredMock.Verify(x => x(consumerSettings, request), Times.Once); // callback called once }
public void When_RequestExpired_Then_OnMessageExpiredIsCalled() { // arrange var onMessageExpiredMock = new Mock <Action <IMessageBus, AbstractConsumerSettings, object> >(); var consumerSettings = new HandlerBuilder <SomeRequest, SomeResponse>(new MessageBusSettings()).Topic(null).WithHandler <IRequestHandler <SomeRequest, SomeResponse> >().Instances(1).ConsumerSettings; consumerSettings.OnMessageExpired = onMessageExpiredMock.Object; var p = new ConsumerInstancePoolMessageProcessor <SomeRequest>(consumerSettings, _busMock.Bus, x => Array.Empty <byte>()); var request = new SomeRequest(); var requestMessage = new MessageWithHeaders(); requestMessage.SetHeader(ReqRespMessageHeaders.Expires, _busMock.CurrentTime.AddSeconds(-10)); _busMock.BusMock.Setup(x => x.DeserializeRequest(typeof(SomeRequest), It.IsAny <byte[]>(), out requestMessage)) .Returns(request); // act p.ProcessMessage(request).Wait(); // assert _busMock.HandlerMock.Verify(x => x.OnHandle(It.IsAny <SomeRequest>(), It.IsAny <string>()), Times.Never); // the handler should not be called onMessageExpiredMock.Verify(x => x(_busMock.Bus, consumerSettings, request), Times.Once); // callback called once }
public void WhenRequestMessageSerializedThenDeserializeGivesSameObject() { // arrange var r = new RequestA(); var rid = "1"; var replyTo = "some_topic"; var expires = DateTimeOffset.UtcNow.AddMinutes(2); var reqMessage = new MessageWithHeaders(); reqMessage.SetHeader(ReqRespMessageHeaders.ReplyTo, replyTo); reqMessage.SetHeader(ReqRespMessageHeaders.RequestId, rid); reqMessage.SetHeader(ReqRespMessageHeaders.Expires, expires); // act var payload = Bus.SerializeRequest(typeof(RequestA), r, reqMessage, new Mock <ProducerSettings>().Object); Bus.DeserializeRequest(typeof(RequestA), payload, out var resMessage); // assert resMessage.Headers[ReqRespMessageHeaders.RequestId].Should().Be(rid); resMessage.Headers[ReqRespMessageHeaders.ReplyTo].Should().Be(replyTo); resMessage.TryGetHeader(ReqRespMessageHeaders.Expires, out DateTimeOffset? resExpires); resExpires.HasValue.Should().BeTrue(); resExpires.Value.ToFileTime().Should().Be(expires.ToFileTime()); }
public override Task ProduceResponse(object request, MessageWithHeaders requestMessage, object response, MessageWithHeaders responseMessage, ConsumerSettings consumerSettings) { var replyTo = requestMessage.Headers[ReqRespMessageHeaders.ReplyTo]; var kind = (PathKind)requestMessage.GetHeaderAsInt(RequestHeaderReplyToKind); var responseMessagePayload = SerializeResponse(consumerSettings.ResponseType, response, responseMessage); return(ProduceToTransport(consumerSettings.ResponseType, response, replyTo, responseMessagePayload, kind)); }
public override byte[] SerializeResponse(Type responseType, object response, MessageWithHeaders responseMessage) { if (!ProviderSettings.EnableMessageSerialization) { // the serialized payload is not going to be used return(null); } return(base.SerializeResponse(responseType, response, responseMessage)); }
public override byte[] SerializeRequest(Type requestType, object request, MessageWithHeaders requestMessage, ProducerSettings producerSettings) { if (!ProviderSettings.EnableMessageSerialization) { // the serialized payload is not going to be used return(null); } return(base.SerializeRequest(requestType, request, requestMessage, producerSettings)); }
public override Task ProduceRequest(object request, MessageWithHeaders requestMessage, string name, ProducerSettings producerSettings) { if (requestMessage is null) { throw new ArgumentNullException(nameof(requestMessage)); } requestMessage.SetHeader(RequestHeaderReplyToKind, (int)Settings.RequestResponse.GetKind()); return(base.ProduceRequest(request, requestMessage, name, producerSettings)); }
public void WithoutHeaders_SerializationWorks() { // arrange var m = new MessageWithHeaders { Payload = _payload }; // act var payload = _serializer.Serialize(typeof(MessageWithHeaders), m); var m2 = (MessageWithHeaders)_serializer.Deserialize(typeof(MessageWithHeaders), payload); // assert m2.Headers.Count.Should().Be(0); _payload.SequenceEqual(m2.Payload).Should().BeTrue(); }
public void WithoutPayload_SerializationWorks() { // arrange var m = new MessageWithHeaders { Payload = null }; // act var payload = _serializer.Serialize(typeof(MessageWithHeaders), m); var m2 = (MessageWithHeaders)_serializer.Deserialize(typeof(MessageWithHeaders), payload); // assert m2.Headers.Count.Should().Be(0); m2.Payload.Should().BeNull(); }
public override Task ProduceResponse(object request, MessageWithHeaders requestMessage, object response, MessageWithHeaders responseMessage, ConsumerSettings consumerSettings) { if (requestMessage is null) { throw new ArgumentNullException(nameof(requestMessage)); } if (consumerSettings is null) { throw new ArgumentNullException(nameof(consumerSettings)); } var replyTo = requestMessage.Headers[ReqRespMessageHeaders.ReplyTo]; var kind = (PathKind)requestMessage.GetHeaderAsInt(RequestHeaderReplyToKind); var responseMessagePayload = SerializeResponse(consumerSettings.ResponseType, response, responseMessage); return(ProduceToTransport(consumerSettings.ResponseType, response, replyTo, responseMessagePayload, kind)); }
public virtual byte[] SerializeRequest(Type requestType, object request, string requestId, string replyTo, DateTimeOffset?expires) { var requestPayload = serializer.Serialize(requestType, request); // create the request wrapper message var requestMessage = new MessageWithHeaders(requestPayload); requestMessage.SetHeader(ReqRespMessageHeaders.RequestId, requestId); requestMessage.SetHeader(ReqRespMessageHeaders.ReplyTo, replyTo); if (expires.HasValue) { requestMessage.SetHeader(ReqRespMessageHeaders.Expires, expires.Value); } var requestMessagePayload = messageWithHeadersSerializer.Serialize(typeof(MessageWithHeaders), requestMessage); return(requestMessagePayload); }
public void WhenRequestFailsThenOnMessageFaultIsCalledAndErrorResponseIsSent() { // arrange var onMessageFaultMock = new Mock <Action <AbstractConsumerSettings, object, Exception> >(); var consumerSettings = new ConsumerSettings { Instances = 1, Topic = "topic1", ConsumerMode = ConsumerMode.RequestResponse, ConsumerType = typeof(IRequestHandler <SomeRequest, SomeResponse>), MessageType = typeof(SomeRequest), OnMessageFault = onMessageFaultMock.Object }; var p = new ConsumerInstancePool <SomeRequest>(consumerSettings, _busMock.Bus, x => Array.Empty <byte>()); var request = new SomeRequest(); var requestMessage = new MessageWithHeaders(); var replyTo = "reply-topic"; var requestId = "request-id"; requestMessage.SetHeader(ReqRespMessageHeaders.RequestId, requestId); requestMessage.SetHeader(ReqRespMessageHeaders.ReplyTo, replyTo); _busMock.BusMock.Setup(x => x.DeserializeRequest(typeof(SomeRequest), It.IsAny <byte[]>(), out requestMessage)) .Returns(request); var ex = new Exception("Something went bad"); _busMock.HandlerMock.Setup(x => x.OnHandle(request, consumerSettings.Topic)) .Returns(Task.FromException <SomeResponse>(ex)); // act p.ProcessMessage(request).Wait(); // assert _busMock.HandlerMock.Verify(x => x.OnHandle(request, consumerSettings.Topic), Times.Once); // handler called once onMessageFaultMock.Verify( x => x(consumerSettings, request, ex), Times.Once); // callback called once _busMock.BusMock.Verify( x => x.ProduceResponse(request, requestMessage, It.IsAny <SomeResponse>(), It.Is <MessageWithHeaders>(m => m.Headers[ReqRespMessageHeaders.RequestId] == requestId), It.IsAny <ConsumerSettings>())); }
public override Task ProduceToTransport(Type messageType, object message, string name, byte[] payload) { var req = DeserializeRequest(messageType, payload, out var requestMessage); var resp = OnReply(messageType, name, req); if (resp == null) { return(Task.CompletedTask); } var respMessage = new MessageWithHeaders(); respMessage.SetHeader(ReqRespMessageHeaders.RequestId, requestMessage.Headers[ReqRespMessageHeaders.RequestId]); var replyTo = requestMessage.Headers[ReqRespMessageHeaders.ReplyTo]; var respPayload = SerializeResponse(resp.GetType(), resp, respMessage); return(OnResponseArrived(respPayload, replyTo)); }
public void WithLargeHeader_SerializationWorks() { // arrange var largeValue = "System.InvalidOperationException: Image with id '_DSC0862.jpg' does not exist\r\n at Sample.Images.Worker.Handlers.GenerateThumbnailRequestHandler.<OnHandle>d__3.MoveNext() in E:\\dev\\mygithub\\SlimMessageBus\\Samples\\Sample.Images.Worker\\Handlers\\GenerateThumbnailRequestHandler.cs:line 31\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at SlimMessageBus.Host.Kafka.TopicConsumerInstances.<ProcessMessage>d__13.MoveNext() in E:\\dev\\mygithub\\SlimMessageBus\\SlimMessageBus.Host.Kafka\\TopicSubscriberInstances.cs:line 109"; var m = new MessageWithHeaders { Payload = _payload, Headers = { { "key1", largeValue } } }; // act var payload = _serializer.Serialize(typeof(MessageWithHeaders), m); var m2 = (MessageWithHeaders)_serializer.Deserialize(typeof(MessageWithHeaders), payload); // assert m2.Headers.Count.Should().Be(1); m2.Headers.ContainsKey("key1").Should().BeTrue(); m2.Headers["key1"].ShouldBeEquivalentTo(largeValue); }
public async Task When_RequestFails_Then_OnMessageFaultIsCalledAndErrorResponseIsSent() { // arrange var onMessageFaultMock = new Mock <Action <IMessageBus, AbstractConsumerSettings, object, Exception, object> >(); var consumerSettings = new HandlerBuilder <SomeRequest, SomeResponse>(new MessageBusSettings()).Topic(null).WithHandler <IRequestHandler <SomeRequest, SomeResponse> >().Instances(1).ConsumerSettings; consumerSettings.OnMessageFault = onMessageFaultMock.Object; var p = new ConsumerInstancePoolMessageProcessor <SomeRequest>(consumerSettings, _busMock.Bus, x => Array.Empty <byte>()); var request = new SomeRequest(); var requestMessage = new MessageWithHeaders(); var replyTo = "reply-topic"; var requestId = "request-id"; requestMessage.SetHeader(ReqRespMessageHeaders.RequestId, requestId); requestMessage.SetHeader(ReqRespMessageHeaders.ReplyTo, replyTo); _busMock.BusMock.Setup(x => x.DeserializeRequest(typeof(SomeRequest), It.IsAny <byte[]>(), out requestMessage)).Returns(request); var ex = new Exception("Something went bad"); _busMock.HandlerMock.Setup(x => x.OnHandle(request, consumerSettings.Topic)).Returns(Task.FromException <SomeResponse>(ex)); // act var exception = await p.ProcessMessage(request); // assert _busMock.HandlerMock.Verify(x => x.OnHandle(request, consumerSettings.Topic), Times.Once); // handler called once onMessageFaultMock.Verify( x => x(_busMock.Bus, consumerSettings, request, ex, It.IsAny <object>()), Times.Once); // callback called once _busMock.BusMock.Verify( x => x.ProduceResponse(request, requestMessage, It.IsAny <SomeResponse>(), It.Is <MessageWithHeaders>(m => m.Headers[ReqRespMessageHeaders.RequestId] == requestId), It.IsAny <ConsumerSettings>())); exception.Should().BeSameAs(ex); }
public override async Task ProduceToTransport([NotNull] Type messageType, object message, string name, [NotNull] byte[] messagePayload, MessageWithHeaders messageWithHeaders = null) { AssertActive(); // calculate message key var key = GetMessageKey(messageType, message, name); var kafkaMessage = new Message { Key = key, Value = messagePayload }; // calculate partition var partition = GetMessagePartition(messageType, message, name); _logger.LogTrace("Producing message {message} of type {messageType}, on topic {topic}, partition {partition}, key size {keySize}, payload size {messageSize}", message, messageType.Name, name, partition, key?.Length ?? 0, messagePayload.Length); // send the message to topic var task = partition == NoPartition ? _producer.ProduceAsync(name, kafkaMessage) : _producer.ProduceAsync(new TopicPartition(name, new Partition(partition)), kafkaMessage); // ToDo: Introduce support for not awaited produce var deliveryResult = await task.ConfigureAwait(false); if (deliveryResult.Status == PersistenceStatus.NotPersisted) { throw new PublishMessageBusException($"Error while publish message {message} of type {messageType.Name} to topic {name}. Kafka persistence status: {deliveryResult.Status}"); } // log some debug information _logger.LogDebug("Message {message} of type {messageType} delivered to topic-partition-offset {topicPartitionOffset}", message, messageType.Name, deliveryResult.TopicPartitionOffset); }
/// <summary> /// /// </summary> /// <param name="messageType"></param> /// <param name="payload"></param> /// <param name="message"></param> /// <param name="name"></param> /// <returns></returns> public override async Task ProduceToTransport(Type messageType, object message, string name, byte[] payload, MessageWithHeaders messageWithHeaders = null) { AssertActive(); _logger.LogDebug("Producing message {0} of type {1} on topic {2} with size {3}", message, messageType.Name, name, payload.Length); var producer = _producerByTopic.GetOrAdd(name); var ev = new EventData(payload); // ToDo: Add support for partition keys await producer.SendAsync(ev).ConfigureAwait(false); _logger.LogDebug("Delivered message {0} of type {1} on topic {2}", message, messageType.Name, name); }
public override async Task ProduceToTransport(Type messageType, object message, string name, byte[] payload, MessageWithHeaders messageWithHeaders = null) { var result = await Database.PublishAsync(name, payload).ConfigureAwait(false); _logger.LogDebug("Produced message {0} of type {1} to redis channel {2} with result {3}", message, messageType, name, result); }
public override Task ProduceToTransport(Type messageType, object message, string name, byte[] payload, MessageWithHeaders messageWithHeaders = null) { // determine the SMB topic name if its a Azure SB queue or topic if (!_kindByTopic.TryGetValue(name, out var kind)) { if (!_kindByMessageType.TryGetValue(messageType, out kind)) { // by default this will be a topic kind = PathKind.Topic; } } return(ProduceToTransport(messageType, message, name, payload, kind)); }
public override Task ProduceToTransport(Type messageType, object message, string name, byte[] messagePayload, MessageWithHeaders messageWithHeaders = null) { if (!_consumersByTopic.TryGetValue(name, out var consumers)) { Log.DebugFormat(CultureInfo.InvariantCulture, "No consumers interested in message type {0} on topic {1}", messageType, name); return(Task.CompletedTask); } var tasks = new LinkedList <Task>(); foreach (var consumer in consumers) { // obtain the consumer from DI Log.DebugFormat(CultureInfo.InvariantCulture, "Resolving consumer type {0}", consumer.ConsumerType); var consumerInstance = Settings.DependencyResolver.Resolve(consumer.ConsumerType); if (consumerInstance == null) { Log.WarnFormat(CultureInfo.InvariantCulture, "The dependency resolver did not yield any instance of {0}", consumer.ConsumerType); continue; } var messageForConsumer = !ProviderSettings.EnableMessageSerialization ? message // prevent deep copy of the message : consumer.ConsumerMode == ConsumerMode.RequestResponse ? DeserializeRequest(messageType, messagePayload, out var _) // will pass a deep copy of the message : DeserializeMessage(messageType, messagePayload); // will pass a deep copy of the message Log.DebugFormat(CultureInfo.InvariantCulture, "Invoking {0} {1}", consumer.ConsumerMode == ConsumerMode.Consumer ? "consumer" : "handler", consumerInstance.GetType()); var task = consumer.ConsumerMethod(consumerInstance, messageForConsumer, consumer.Topic); if (consumer.ConsumerMode == ConsumerMode.RequestResponse) { var requestId = messageWithHeaders.Headers[ReqRespMessageHeaders.RequestId]; task = task.ContinueWith(x => { if (x.IsFaulted || x.IsCanceled) { return(OnResponseArrived(null, name, requestId, x.IsCanceled ? "Cancelled" : x.Exception.Message, null)); } var response = consumer.ConsumerMethodResult(x); var responsePayload = SerializeMessage(consumer.ResponseType, response); return(OnResponseArrived(responsePayload, name, requestId, null, response)); }, TaskScheduler.Current).Unwrap(); } tasks.AddLast(task); } Log.DebugFormat(CultureInfo.InvariantCulture, "Waiting on {0} consumer tasks", tasks.Count); return(Task.WhenAll(tasks)); }
public override Task ProduceRequest(object request, MessageWithHeaders requestMessage, string name, ProducerSettings producerSettings) { requestMessage.SetHeader(RequestHeaderReplyToKind, (int)Settings.RequestResponse.GetKind()); return(base.ProduceRequest(request, requestMessage, name, producerSettings)); }
public override Task ProduceToTransport(Type messageType, object message, string name, byte[] messagePayload, MessageWithHeaders messageWithHeaders = null) { if (!_consumersByTopic.TryGetValue(name, out var consumers)) { _logger.LogDebug("No consumers interested in message type {messageType} on topic {topic}", messageType, name); return(Task.CompletedTask); } var tasks = new LinkedList <Task>(); foreach (var consumer in consumers) { var task = OnMessageProduced(messageType, message, name, messagePayload, messageWithHeaders, consumer); if (task != null) { tasks.AddLast(task); } } _logger.LogDebug("Waiting on {0} consumer tasks", tasks.Count); return(Task.WhenAll(tasks)); }
private async Task OnMessageProduced(Type messageType, object message, string name, byte[] messagePayload, MessageWithHeaders messageWithHeaders, ConsumerSettings consumer) { // ToDo: Extension: In case of IMessageBus.Publish do not wait for the consumer method see https://github.com/zarusz/SlimMessageBus/issues/37 string responseError = null; Task consumerTask = null; try { consumerTask = await ExecuteConsumer(messageType, message, messagePayload, consumer).ConfigureAwait(false); } #pragma warning disable CA1031 // Intended, a catch all situation catch (Exception e) #pragma warning restore CA1031 { responseError = e.Message; } if (consumer.ConsumerMode == ConsumerMode.RequestResponse) { var requestId = messageWithHeaders.Headers[ReqRespMessageHeaders.RequestId]; if (responseError != null) { await OnResponseArrived(null, name, requestId, responseError, null).ConfigureAwait(false); } else { var response = consumer.ConsumerMethodResult(consumerTask); var responsePayload = SerializeMessage(consumer.ResponseType, response); await OnResponseArrived(responsePayload, name, requestId, null, response).ConfigureAwait(false); } } }
public override async Task ProduceToTransport(Type messageType, object message, string name, byte[] payload, MessageWithHeaders messageWithHeaders = null) { AssertActive(); // calculate message key var key = GetMessageKey(messageType, message, name); // calculate partition var partition = GetMessagePartition(messageType, message, name); _logger.LogTrace("Producing message {0} of type {1}, on topic {2}, partition {3}, key length {4}, payload size {5}", message, messageType.Name, name, partition, key?.Length ?? 0, payload.Length); // send the message to topic var task = partition == NoPartition ? _producer.ProduceAsync(name, key, payload) : _producer.ProduceAsync(name, key, 0, key?.Length ?? 0, payload, 0, payload.Length, partition); var deliveryReport = await task.ConfigureAwait(false); if (deliveryReport.Error.HasError) { throw new PublishMessageBusException($"Error while publish message {message} of type {messageType.Name} to topic {name}. Kafka response code: {deliveryReport.Error.Code}, reason: {deliveryReport.Error.Reason}"); } // log some debug information _logger.LogDebug("Message {0} of type {1} delivered to topic-partition-offset {2}", message, messageType.Name, deliveryReport.TopicPartitionOffset); }