public void WhenMessageFails_OnMessageFault_IsCalled() { // arrange var onMessageFaultMock = new Mock <Action <ConsumerSettings, object, Exception> >(); var consumerSettings = new ConsumerSettings { Instances = 1, Topic = "topic1", ConsumerMode = ConsumerMode.Subscriber, ConsumerType = typeof(IConsumer <SomeMessage>), MessageType = typeof(SomeMessage), OnMessageFault = onMessageFaultMock.Object }; var p = new ConsumerInstancePool <SomeMessage>(consumerSettings, _busMock.Object, x => new byte[0]); var message = new SomeMessage(); _serializerMock.Setup(x => x.Deserialize(typeof(SomeMessage), It.IsAny <byte[]>())).Returns(message); var ex = new Exception("Something went bad"); _consumerMock.Setup(x => x.OnHandle(message, consumerSettings.Topic)).Returns(Task.FromException <SomeResponse>(ex)); // act p.Submit(message); var commitedMsg = p.Commit(message); // assert commitedMsg.Should().BeSameAs(message); // it should commit the failed message _consumerMock.Verify(x => x.OnHandle(message, consumerSettings.Topic), Times.Once); // handler called once onMessageFaultMock.Verify(x => x(consumerSettings, message, ex), Times.Once); // callback called once }
public void WhenRequestExpired_OnMessageExpired_IsCalled() { // arrange var onMessageExpiredMock = new Mock <Action <ConsumerSettings, 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.Object, x => new byte[0]); var request = new SomeRequest(); string requestId; string replyTo; DateTimeOffset?expires = _currentTime.AddSeconds(-10); _busMock.Setup(x => x.DeserializeRequest(typeof(SomeRequest), It.IsAny <byte[]>(), out requestId, out replyTo, out expires)).Returns(request); // act p.Submit(request); var commitedMsg = p.Commit(request); // assert commitedMsg.Should().BeSameAs(request); // it should commit the request message _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 WhenMessageFailsThenOnMessageFaultIsCalled() { // arrange var onMessageFaultMock = new Mock <Action <AbstractConsumerSettings, object, Exception> >(); var consumerSettings = new ConsumerSettings { Instances = 1, Topic = "topic1", ConsumerMode = ConsumerMode.Consumer, ConsumerType = typeof(IConsumer <SomeMessage>), MessageType = typeof(SomeMessage), OnMessageFault = onMessageFaultMock.Object }; var p = new ConsumerInstancePool <SomeMessage>(consumerSettings, _busMock.Bus, x => Array.Empty <byte>()); var message = new SomeMessage(); _busMock.SerializerMock.Setup(x => x.Deserialize(typeof(SomeMessage), It.IsAny <byte[]>())).Returns(message); var ex = new Exception("Something went bad"); _busMock.ConsumerMock.Setup(x => x.OnHandle(message, consumerSettings.Topic)) .Returns(Task.FromException <SomeResponse>(ex)); // act p.ProcessMessage(message).Wait(); // assert _busMock.ConsumerMock.Verify(x => x.OnHandle(message, consumerSettings.Topic), Times.Once); // handler called once onMessageFaultMock.Verify(x => x(consumerSettings, message, ex), Times.Once); // callback called once }
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 AfterCreation_ResolvesNInstancesOfHandler() { // arrange var consumerSettings = new ConsumerSettings { Instances = 2, ConsumerMode = ConsumerMode.RequestResponse, ConsumerType = typeof(IRequestHandler <SomeRequest, SomeResponse>), MessageType = typeof(SomeRequest) }; // act var p = new ConsumerInstancePool <SomeRequest>(consumerSettings, _busMock.Object, x => new byte[0]); // assert _dependencyResolverMock.Verify(x => x.Resolve(typeof(IRequestHandler <SomeRequest, SomeResponse>)), Times.Exactly(consumerSettings.Instances)); }
public void WhenNewInstanceThenResolvesNInstancesOfConsumer() { // arrange var consumerSettings = new ConsumerSettings { Instances = 2, ConsumerMode = ConsumerMode.Consumer, ConsumerType = typeof(IConsumer <SomeMessage>), MessageType = typeof(SomeMessage) }; // act var p = new ConsumerInstancePool <SomeMessage>(consumerSettings, _busMock.Bus, x => Array.Empty <byte>()); // assert _busMock.DependencyResolverMock.Verify(x => x.Resolve(typeof(IConsumer <SomeMessage>)), Times.Exactly(consumerSettings.Instances)); }
public void AfterCreation_ResolvesNInstancesOfConsumer() { // arrange var consumerSettings = new ConsumerSettings { Instances = 2, ConsumerMode = ConsumerMode.Subscriber, ConsumerType = typeof(IConsumer <SomeMessage>), MessageType = typeof(SomeMessage) }; // act var p = new ConsumerInstancePool <SomeMessage>(consumerSettings, _busMock.Object, x => new byte[0]); // assert _busMock.DependencyResolverMock.Verify(x => x.Resolve(typeof(IConsumer <SomeMessage>)), Times.Exactly(consumerSettings.Instances)); }
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>())); }
protected void CreateConsumers() { var subscriber = Connection.GetSubscriber(); Log.Info("Creating consumers"); foreach (var consumerSettings in Settings.Consumers) { Log.InfoFormat(CultureInfo.InvariantCulture, "Creating consumer for {0}", consumerSettings.FormatIf(Log.IsInfoEnabled)); var messageProcessor = new ConsumerInstancePool <byte[]>(consumerSettings, this, m => m); AddConsumer(consumerSettings, subscriber, messageProcessor); } if (Settings.RequestResponse != null) { Log.InfoFormat(CultureInfo.InvariantCulture, "Creating response consumer for {0}", Settings.RequestResponse.FormatIf(Log.IsInfoEnabled)); var messageProcessor = new ResponseMessageProcessor <byte[]>(Settings.RequestResponse, this, m => m); AddConsumer(Settings.RequestResponse, subscriber, messageProcessor); } }
public void WhenRequestFails_OnMessageFault_IsCalled_And_ErrorResponse_IsSent() { // arrange var onMessageFaultMock = new Mock <Action <ConsumerSettings, 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.Object, x => new byte[0]); var request = new SomeRequest(); string requestId; string replyTo = "reply-topic"; DateTimeOffset?expires; _busMock.Setup(x => x.DeserializeRequest(typeof(SomeRequest), It.IsAny <byte[]>(), out requestId, out replyTo, out expires)).Returns(request); var ex = new Exception("Something went bad"); _handlerMock.Setup(x => x.OnHandle(request, consumerSettings.Topic)).Returns(Task.FromException <SomeResponse>(ex)); // act p.Submit(request); var commitedMsg = p.Commit(request); // assert commitedMsg.Should().BeSameAs(request); // it should commit the failed request message _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.Verify(x => x.Publish(typeof(SomeResponse), It.IsAny <byte[]>(), replyTo)); }
public ServiceBusMessageBus(MessageBusSettings settings, ServiceBusMessageBusSettings serviceBusSettings) : base(settings) { ServiceBusSettings = serviceBusSettings; _producerByTopic = new SafeDictionaryWrapper <string, ITopicClient>(topic => { Log.DebugFormat(CultureInfo.InvariantCulture, $"Creating {nameof(ITopicClient)} for name {0}", topic); return(ServiceBusSettings.TopicClientFactory(topic)); }); _producerByQueue = new SafeDictionaryWrapper <string, IQueueClient>(queue => { Log.DebugFormat(CultureInfo.InvariantCulture, $"Creating {nameof(IQueueClient)} for name {0}", queue); return(ServiceBusSettings.QueueClientFactory(queue)); }); foreach (var producerSettings in settings.Producers) { var producerKind = producerSettings.GetKind(); PathKind existingKind; var topic = producerSettings.DefaultTopic; if (topic != null) { if (_kindByTopic.TryGetValue(topic, out existingKind)) { if (existingKind != producerKind) { throw new InvalidConfigurationMessageBusException($"The same name '{topic}' was used for queue and topic. You cannot share one name for a topic and queue. Please fix your configuration."); } } else { _kindByTopic.Add(topic, producerKind); } } if (_kindByMessageType.TryGetValue(producerSettings.MessageType, out existingKind)) { if (existingKind != producerKind) { throw new InvalidConfigurationMessageBusException($"The same message type '{producerSettings.MessageType}' was used for queue and topic. You cannot share one message type for a topic and queue. Please fix your configuration."); } } else { _kindByMessageType.Add(producerSettings.MessageType, producerKind); } } Log.Info("Creating consumers"); foreach (var consumerSettings in settings.Consumers) { Log.InfoFormat(CultureInfo.InvariantCulture, "Creating consumer for {0}", consumerSettings.FormatIf(Log.IsInfoEnabled)); var messageProcessor = new ConsumerInstancePool <Message>(consumerSettings, this, m => m.Body); AddConsumer(consumerSettings, messageProcessor); } if (settings.RequestResponse != null) { Log.InfoFormat(CultureInfo.InvariantCulture, "Creating response consumer for {0}", settings.RequestResponse.FormatIf(Log.IsInfoEnabled)); var messageProcessor = new ResponseMessageProcessor <Message>(settings.RequestResponse, this, m => m.Body); AddConsumer(settings.RequestResponse, messageProcessor); } }
public void Ensure_ExactlyNConsumerInstancesAreWorking() { const int consumerTime = 500; const int consumerInstances = 8; const int messageCount = 500; // arrange var consumerSettings = new ConsumerSettings { Instances = consumerInstances, ConsumerMode = ConsumerMode.Subscriber, ConsumerType = typeof(IConsumer <SomeMessage>), MessageType = typeof(SomeMessage) }; var activeInstances = 0; var processedMessageCount = 0; var maxInstances = 0; var maxInstancesLock = new object(); _consumerMock.Setup(x => x.OnHandle(It.IsAny <SomeMessage>(), It.IsAny <string>())) .Returns((SomeMessage msg, string topic) => { Interlocked.Increment(ref activeInstances); lock (maxInstancesLock) { // capture maximum active maxInstances = Math.Max(maxInstances, activeInstances); } return(Task .Delay(consumerTime) .ContinueWith(t => { Interlocked.Decrement(ref activeInstances); Interlocked.Increment(ref processedMessageCount); })); }); var p = new ConsumerInstancePool <SomeMessage>(consumerSettings, _busMock.Object, x => new byte[0]); // act var time = Stopwatch.StartNew(); SomeMessage lastMsg = null; for (var i = 0; i < messageCount; i++) { lastMsg = new SomeMessage(); p.Submit(lastMsg); } var commitedMsg = p.Commit(lastMsg); time.Stop(); // assert var minPossibleTime = messageCount * consumerTime / consumerSettings.Instances; var maxPossibleTime = messageCount * consumerTime; processedMessageCount.ShouldBeEquivalentTo(messageCount); commitedMsg.Should().BeSameAs(lastMsg); // no errors occured maxInstances.ShouldBeEquivalentTo(consumerSettings.Instances); // max concurrent consumers should reach number of desired instances time.ElapsedMilliseconds.Should().BeInRange(minPossibleTime, maxPossibleTime); var percent = Math.Round(100f * (time.ElapsedMilliseconds - minPossibleTime) / (maxPossibleTime - minPossibleTime), 2); Log.InfoFormat("The execution time was {0}% away from the best possible time", percent); // smallest number is better }
public void WhenNInstancesConfiguredThenExactlyNConsumerInstancesAreWorking() { const int consumerTime = 500; const int consumerInstances = 8; const int messageCount = 500; // arrange var consumerSettings = new ConsumerSettings { Instances = consumerInstances, ConsumerMode = ConsumerMode.Consumer, ConsumerType = typeof(IConsumer <SomeMessage>), MessageType = typeof(SomeMessage) }; var activeInstances = 0; var processedMessageCount = 0; var maxInstances = 0; var maxInstancesLock = new object(); _busMock.ConsumerMock.Setup(x => x.OnHandle(It.IsAny <SomeMessage>(), It.IsAny <string>())) .Returns((SomeMessage msg, string topic) => { Interlocked.Increment(ref activeInstances); lock (maxInstancesLock) { // capture maximum active maxInstances = Math.Max(maxInstances, activeInstances); } return(Task .Delay(consumerTime) .ContinueWith(t => { Interlocked.Decrement(ref activeInstances); Interlocked.Increment(ref processedMessageCount); }, TaskScheduler.Current)); }); var p = new ConsumerInstancePool <SomeMessage>(consumerSettings, _busMock.Bus, x => Array.Empty <byte>()); // act var time = Stopwatch.StartNew(); var tasks = new Task[messageCount]; for (var i = 0; i < messageCount; i++) { tasks[i] = p.ProcessMessage(new SomeMessage()); } Task.WaitAll(tasks); time.Stop(); // assert var minPossibleTime = messageCount * consumerTime / consumerSettings.Instances; var maxPossibleTime = messageCount * consumerTime; processedMessageCount.Should().Be(messageCount); maxInstances.Should().Be(consumerSettings.Instances); // max concurrent consumers should reach number of desired instances time.ElapsedMilliseconds.Should().BeInRange(minPossibleTime, maxPossibleTime); var percent = Math.Round(100f * (time.ElapsedMilliseconds - minPossibleTime) / (maxPossibleTime - minPossibleTime), 2); Log.InfoFormat(CultureInfo.InvariantCulture, "The execution time was {0}% away from the best possible time", percent); // smallest number is better }