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"));
        }
示例#2
0
    /// <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>();
        }
示例#4
0
    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>()));
    }
示例#5
0
        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));
        }
示例#7
0
    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;
        }
    }
示例#8
0
    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));
    }
示例#9
0
        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();
        }
示例#11
0
    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);
    }