public async Task ThreeMiddlewares_ShouldExecuteInCorrectOrder() { var callRecord = new List <string>(); void Before(string id) => callRecord.Add($"Before_{id}"); void After(string id) => callRecord.Add($"After_{id}"); var outer = new TrackingMiddleware("outer", Before, After); var middle = new TrackingMiddleware("middle", Before, After); var inner = new TrackingMiddleware("inner", Before, After); var middleware = new HandlerMiddlewareBuilder(_resolver, _resolver) .Configure(pipe => { pipe.Use(outer); pipe.Use(middle); pipe.Use(inner); }).Build(); var context = new HandleMessageContext(new SimpleMessage(), typeof(SimpleMessage), "a-fake-queue"); await middleware.RunAsync(context, ct => { callRecord.Add("HandledMessage"); return(Task.FromResult(true)); }, CancellationToken.None); var record = string.Join(Environment.NewLine, callRecord); record.ShouldMatchApproved(c => c.SubFolder("Approvals")); }
/// <summary> /// A convenience method to get a message as <typeparamref name="TMessage"/> from the context. /// </summary> /// <param name="context">The context to get the message from.</param> /// <typeparam name="TMessage">The type of the message to try and get from the context.</typeparam> /// <returns>An instance of <typeparamref name="TMessage"/> or <see langword="null"/> if the message was not of type <typeparamref name="TMessage"/></returns> /// <exception cref="ArgumentNullException">The <see cref="context"/> object is <see langword="null"/>.</exception> public static TMessage MessageAs <TMessage>(this HandleMessageContext context) where TMessage : Message { if (context == null) { throw new ArgumentNullException(nameof(context)); } return(context.Message as TMessage); }
public async Task WhenMiddlewareIsWrappedinStopWatch_InnerMiddlewareIsCalled() { var context = new HandleMessageContext(new OrderAccepted(), typeof(OrderAccepted), "test-queue"); var result = await _middleware.RunAsync(context, null, CancellationToken.None); result.ShouldBeTrue(); _handler.ReceivedMessages.ShouldHaveSingleItem().ShouldBeOfType <OrderAccepted>(); }
protected override async Task <bool> RunInnerAsync( HandleMessageContext context, Func <CancellationToken, Task <bool> > func, CancellationToken stoppingToken) { if (context == null) { throw new ArgumentNullException(nameof(context)); } return(await _func(context.MessageAs <TMessage>())); }
private async Task <bool> CallMessageHandler(string queueName, Message message, CancellationToken cancellationToken) { var messageType = message.GetType(); var middleware = _middlewareMap.Get(queueName, messageType); if (middleware == null) { _logger.LogError( "Failed to dispatch. Middleware for message of type '{MessageTypeName}' not found in middleware map.", message.GetType().FullName); return(false); } var watch = System.Diagnostics.Stopwatch.StartNew(); using (_messagingMonitor.MeasureDispatch()) { bool dispatchSuccessful = false; try { var context = new HandleMessageContext(message, messageType, queueName); dispatchSuccessful = await middleware.RunAsync(context, null, cancellationToken) .ConfigureAwait(false); } finally { watch.Stop(); var logMessage = "{Status} handling message with Id '{MessageId}' of type {MessageType} in {TimeToHandle}ms."; if (dispatchSuccessful) { _logger.LogInformation(logMessage, "Succeeded", message.Id, messageType, watch.ElapsedMilliseconds); } else { _logger.LogWarning(logMessage, "Failed", message.Id, messageType, watch.ElapsedMilliseconds); } } return(dispatchSuccessful); } }
public async Task WhenMiddlewareIsWrappedinStopWatch_MonitoringIsCalled() { var context = new HandleMessageContext(new OrderAccepted(), typeof(OrderAccepted), "test-queue"); var result = await _middleware.RunAsync(context, null, CancellationToken.None); result.ShouldBeTrue(); var handled = _monitor.HandlerExecutionTimes.ShouldHaveSingleItem(); handled.duration.ShouldBeGreaterThan(TimeSpan.Zero); handled.handlerType.ShouldBe(typeof(InspectableHandler <OrderAccepted>)); handled.messageType.ShouldBe(typeof(OrderAccepted)); }
protected override async Task <bool> RunInnerAsync(HandleMessageContext context, Func <CancellationToken, Task <bool> > func, CancellationToken stoppingToken) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (func == null) { throw new ArgumentNullException(nameof(func)); } string lockKey = $"{context.Message.UniqueKey()}-{_lockSuffixKeyForHandler}"; MessageLockResponse lockResponse = await _messageLock.TryAcquireLockAsync(lockKey, _timeout).ConfigureAwait(false); if (!lockResponse.DoIHaveExclusiveLock) { if (lockResponse.IsMessagePermanentlyLocked) { _logger.LogDebug("Failed to acquire lock for message with key {MessageLockKey} as it is permanently locked.", lockKey); return(RemoveTheMessageFromTheQueue); } _logger.LogDebug("Failed to acquire lock for message with key {MessageLockKey}; returning message to queue.", lockKey); return(LeaveItInTheQueue); } try { _logger.LogDebug("Acquired lock for message with key {MessageLockKey}.", lockKey); bool successfullyHandled = await func(stoppingToken).ConfigureAwait(false); if (successfullyHandled) { await _messageLock.TryAcquireLockPermanentlyAsync(lockKey).ConfigureAwait(false); _logger.LogDebug("Acquired permanent lock for message with key {MessageLockKey}.", lockKey); } return(successfullyHandled); } catch (Exception) { await _messageLock.ReleaseLockAsync(lockKey).ConfigureAwait(false); _logger.LogDebug("Released lock for message with key {MessageLockKey}.", lockKey); throw; } }
protected override async Task <bool> RunInnerAsync( HandleMessageContext context, Func <CancellationToken, Task <bool> > func, CancellationToken stoppingToken) { if (context == null) { throw new ArgumentNullException(nameof(context)); } stoppingToken.ThrowIfCancellationRequested(); var resolutionContext = new HandlerResolutionContext(context.QueueName); IHandlerAsync <T> handler = _handlerResolver(resolutionContext); return(await handler.Handle(context.MessageAs <T>()).ConfigureAwait(false)); }
public async Task DispatchMessageAsync( IQueueMessageContext messageContext, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return; } (bool success, Message typedMessage, MessageAttributes attributes) = await DeserializeMessage(messageContext, cancellationToken).ConfigureAwait(false); if (!success) { return; } var messageType = typedMessage.GetType(); var middleware = _middlewareMap.Get(messageContext.QueueName, messageType); if (middleware == null) { _logger.LogError( "Failed to dispatch. Middleware for message of type '{MessageTypeName}' not found in middleware map.", typedMessage.GetType().FullName); return; } var handleContext = new HandleMessageContext( messageContext.QueueName, messageContext.Message, typedMessage, messageType, messageContext, messageContext, messageContext.QueueUri, attributes); await middleware.RunAsync(handleContext, null, cancellationToken) .ConfigureAwait(false); }
public async Task WhenMessageIsLockedByAnotherHandler_MessageWillBeLeftInTheQueue() { var messageLock = new FakeMessageLock(false); var testResolver = new FakeServiceResolver(sc => sc .AddLogging(l => l.AddXUnit(_outputHelper)) .AddSingleton <IMessageLockAsync>(messageLock)); var handler = new InspectableHandler <OrderAccepted>(); var middleware = new HandlerMiddlewareBuilder(testResolver, testResolver) .UseExactlyOnce <OrderAccepted>(nameof(InspectableHandler <OrderAccepted>), TimeSpan.FromSeconds(1)) .UseHandler(ctx => handler) .Build(); var context = new HandleMessageContext(new OrderAccepted(), typeof(OrderAccepted), "test-queue"); var result = await middleware.RunAsync(context, null, CancellationToken.None); handler.ReceivedMessages.ShouldBeEmpty(); result.ShouldBeFalse(); }
protected override async Task <bool> RunInnerAsync(HandleMessageContext context, Func <CancellationToken, Task <bool> > func, CancellationToken stoppingToken) { await Handler.Handle(context.MessageAs <TMessage>()).ConfigureAwait(false); return(true); }