コード例 #1
0
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            // stashes the current implementation of IDataBusStorage in the context for DataBusAttachment to find
            context.Save(DataBusStorageKey, _dataBusStorage);

            await next().ConfigureAwait(false);
        }
コード例 #2
0
        async Task HandleRoutingSlip(IncomingStepContext context, Message message)
        {
            var transactionContext = context.Load <ITransactionContext>();
            var transportMessage   = await _serialier.Serialize(message).ConfigureAwait(false);

            var headers = transportMessage.Headers;

            var itinerary       = GetDestinations(headers, Headers.RoutingSlipItinerary);
            var nextDestination = itinerary.FirstOrDefault();

            if (nextDestination == null)
            {
                // no more destinations - stop forwarding it now
                return;
            }

            var remainingDestinations = itinerary.Skip(1);

            transportMessage.Headers[Headers.RoutingSlipItinerary] = string.Join(";", remainingDestinations);

            var travelogue = GetDestinations(transportMessage.Headers, Headers.RoutingSlipTravelogue);

            travelogue.Add(_transport.Address);

            transportMessage.Headers[Headers.RoutingSlipTravelogue] = string.Join(";", travelogue);
            transportMessage.Headers[Headers.CorrelationSequence]   = GetNextSequenceNumber(transportMessage.Headers);

            await _transport.Send(nextDestination, transportMessage, transactionContext).ConfigureAwait(false);
        }
コード例 #3
0
        /// <summary>
        /// Checks if there are any registered exceptions to the current message and
        /// if all of them are <see cref="FailFastException"/>, then mark the message
        /// as failed too many times.
        /// </summary>
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            try
            {
                await next();

                var deadletterCommand = context.Load <ManualDeadletterCommand>();

                if (deadletterCommand != null)
                {
                    await ProcessDeadletterCommand(context, deadletterCommand);
                }
            }
            catch (Exception exception)
            {
                var transportMessage = context.Load <TransportMessage>();
                var messageId        = transportMessage.GetMessageId();
                if (_failFastChecker.ShouldFailFast(messageId, exception))
                {
                    // if we're currently executing a 2nd level retry, it's the 2nd level surrogate message ID we must mark as final
                    var messageIdToMarkAsFinal = context.Load <bool>(SimpleRetryStrategyStep.DispatchAsFailedMessageKey)
                        ? SimpleRetryStrategyStep.GetSecondLevelMessageId(messageId)
                        : messageId;

                    _errorTracker.MarkAsFinal(messageIdToMarkAsFinal);
                }
                throw;
            }
        }
コード例 #4
0
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var message = context.Load <Message>();

            var hasInReplyToHeader = message.Headers.TryGetValue(Headers.InReplyTo, out var inReplyToMessageId);

            if (hasInReplyToHeader)
            {
                var isRequestReplyCorrelationId = inReplyToMessageId.StartsWith(SpecialMessageIdPrefix);

                if (isRequestReplyCorrelationId)
                {
                    // if we could successfully remove the task completion source for the request message ID,
                    // we can complete it here
                    if (_messages.TryRemove(inReplyToMessageId, out var taskCompletionSource))
                    {
                        taskCompletionSource.SetResult(message);

                        // abort anything else in the pipeline
                        return;
                    }

                    _log.Warn("Received message with message ID {messageId}, which was determined to be a reply to be handled as an inline request-reply reply (because of the {prefix} prefix), BUT the dictionary of task completion sources did NOT contain an entry for that ID",
                              inReplyToMessageId, SpecialMessageIdPrefix);
                }
            }

            await next();
        }
コード例 #5
0
        /// <summary>
        /// Invokes the routing function and performs some action depending on the returned <see cref="ForwardAction"/> result
        /// </summary>
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var transportMessage = context.Load <TransportMessage>();
            var routingResult    = (await _routingFunction(transportMessage)) ?? ForwardAction.None;
            var actionType       = routingResult.ActionType;

            switch (actionType)
            {
            case ActionType.Forward:
                var destinationAddresses = routingResult.DestinationAddresses;
                var transactionContext   = context.Load <ITransactionContext>();

                _log.Debug("Forwarding {0} to {1}", transportMessage.GetMessageLabel(), string.Join(", ", destinationAddresses));

                await Task.WhenAll(
                    destinationAddresses
                    .Select(address => _transport.Send(address, transportMessage, transactionContext))
                    );

                break;

            case ActionType.None:
                await next();

                break;

            default:
                await next();

                break;
            }
        }
コード例 #6
0
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var message = context.Load <Message>();
            var args    = new MessageHandledEventHandlerArgs();
            var bus     = _bus.Value;

            foreach (var e in _beforeMessageHandled)
            {
                e(bus, message.Headers, message.Body, context, args);
            }

            try
            {
                await next();

                foreach (var e in _afterMessageHandled)
                {
                    e(bus, message.Headers, message.Body, context, args);
                }
            }
            catch (Exception exception)
            {
                context.Save(exception);

                foreach (var e in _afterMessageHandled)
                {
                    e(bus, message.Headers, message.Body, context, args);
                }

                if (!args.IgnoreException)
                {
                    throw;
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Checks the loaded saga data to see if the message currently being handled is a duplicate of a message that has previously been handled.
        /// If that is the case, message dispatch is skipped, but any messages stored as outgoing messages from previously handling the incoming message will be sent.
        /// </summary>
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var handlerInvokersForSagas = context.Load <HandlerInvokers>()
                                          .Where(l => l.HasSaga)
                                          .ToList();

            var message   = context.Load <Message>();
            var messageId = message.GetMessageId();

            var transactionContext = context.Load <ITransactionContext>();

            foreach (var handlerInvoker in handlerInvokersForSagas)
            {
                if (!(handlerInvoker.GetSagaData() is IIdempotentSagaData sagaData))
                {
                    continue;
                }

                var idempotencyData = sagaData.IdempotencyData
                                      ?? (sagaData.IdempotencyData = new IdempotencyData());

                if (idempotencyData.HasAlreadyHandled(messageId))
                {
                    _log.Info("Message with ID {messageId} has already been handled by saga with ID {sagaDataId}",
                              messageId, sagaData.Id);

                    var outgoingMessages = idempotencyData
                                           .GetOutgoingMessages(messageId)
                                           .ToList();

                    if (outgoingMessages.Any())
                    {
                        _log.Info("Found {messageCount} outgoing messages to be (re-)sent... will do that now",
                                  outgoingMessages.Count);

                        foreach (var messageToResend in outgoingMessages)
                        {
                            foreach (var destinationAddress in messageToResend.DestinationAddresses)
                            {
                                var transportMessage = messageToResend.TransportMessage;

                                await _transport.Send(destinationAddress, transportMessage, transactionContext).ConfigureAwait(false);
                            }
                        }
                    }
                    else
                    {
                        _log.Info("Found no outgoing messages to be (re-)sent...");
                    }

                    handlerInvoker.SkipInvocation();
                }
                else
                {
                    idempotencyData.MarkMessageAsHandled(messageId);
                }
            }

            await next().ConfigureAwait(false);
        }
コード例 #8
0
 private static void SendBeforeProcessEvent(IncomingStepContext context, Activity?activity)
 {
     if (DiagnosticListener.IsEnabled(BeforeProcessMessage.EventName, context))
     {
         DiagnosticListener.Write(BeforeProcessMessage.EventName, new BeforeProcessMessage(context, activity));
     }
 }
コード例 #9
0
        void PossiblyDecompressTransportMessage(IncomingStepContext context)
        {
            var transportMessage = context.Load <TransportMessage>();

            string contentEncoding;

            if (!transportMessage.Headers.TryGetValue(Headers.ContentEncoding, out contentEncoding))
            {
                return;
            }

            if (contentEncoding != ZipMessagesOutgoingStep.GzipEncodingHeader)
            {
                var message = $"The message {transportMessage.GetMessageLabel()} has a '{Headers.ContentEncoding}' with the" +
                              $" value '{contentEncoding}', but this middleware only knows how to decompress" +
                              $" '{ZipMessagesOutgoingStep.GzipEncodingHeader}'";

                throw new ArgumentException(message);
            }

            var headers        = transportMessage.Headers.Clone();
            var compressedBody = transportMessage.Body;

            headers.Remove(Headers.ContentEncoding);

            var body = _zipper.Unzip(compressedBody);

            context.Save(new TransportMessage(headers, body));
        }
コード例 #10
0
        public Task Process(OutgoingStepContext context, Func <Task> next)
        {
            Message message = context.Load <Message>();

            if (message.Headers.ContainsKey(Headers.CorrelationId))
            {
                return(next());
            }

            string correlationId = _correlationContextAccessor.CorrelationContext?.CorrelationId ?? _correlationIdFactory.Create();

            message.Headers[Headers.CorrelationId] = correlationId;

            int correlationSequence = 0;
            ITransactionContext transactionContext  = context.Load <ITransactionContext>();
            IncomingStepContext incomingStepContext = transactionContext.GetOrNull <IncomingStepContext>(StepContext.StepContextKey);

            if (incomingStepContext != null)
            {
                correlationSequence = GetCorrelationSequence(incomingStepContext) + 1;
            }

            message.Headers[Headers.CorrelationSequence] = correlationSequence.ToString(CultureInfo.InvariantCulture);

            _logger.Debug("Correlation ID: {CorrelationId}, sequence: {CorrelationSequence}", correlationId, correlationSequence);

            return(next());
        }
コード例 #11
0
 private static void SendAfterProcessEvent(Activity?activity, IncomingStepContext context)
 {
     if (DiagnosticListener.IsEnabled(AfterProcessMessage.EventName))
     {
         DiagnosticListener.Write(AfterProcessMessage.EventName, new AfterProcessMessage(context, activity));
     }
 }
コード例 #12
0
        /// <summary>
        /// Checks to see if the incoming message has the <see cref="Headers.DeferredUntil"/> header. If that is the case, the message is either stored for later delivery
        /// or forwarded to the configured external timeout manager. If not, the message will be passed on down the pipeline.
        /// </summary>
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var transportMessage = context.Load <TransportMessage>();

            string deferredUntil;

            var headers = transportMessage.Headers;

            if (!headers.TryGetValue(Headers.DeferredUntil, out deferredUntil))
            {
                await next();

                return;
            }

            if (!headers.ContainsKey(Headers.ReturnAddress))
            {
                throw new ApplicationException(string.Format("Received message {0} with the '{1}' header set to '{2}', but the message had no '{3}' header!",
                                                             headers[Headers.MessageId],
                                                             Headers.DeferredUntil,
                                                             headers[Headers.DeferredUntil],
                                                             Headers.ReturnAddress));
            }

            if (UsingExternalTimeoutManager)
            {
                var transactionContext = context.Load <ITransactionContext>();

                await ForwardMessageToExternalTimeoutManager(transportMessage, transactionContext);
            }
            else
            {
                await StoreMessageUntilDue(deferredUntil, headers, transportMessage);
            }
        }
コード例 #13
0
        /// <summary>
        /// Processes the message
        /// </summary>
        public async Task Process(IncomingStepContext context, Func<Task> next)
        {
            var invokers = context.Load<HandlerInvokers>();
            var didInvokeHandler = false;

            foreach (var invoker in invokers)
            {
                await invoker.Invoke();
                didInvokeHandler = true;
            }

            if (!didInvokeHandler)
            {
                var message = context.Load<Message>();
                
                var messageId = message.GetMessageId();
                var messageType = message.GetMessageType();

                var text = string.Format("Message with ID {0} and type {1} could not be dispatched to any handlers",
                    messageId, messageType);

                throw new RebusApplicationException(text);
            }

            await next();
        }
コード例 #14
0
            public async Task Process(IncomingStepContext context, Func <Task> next)
            {
                var serviceProvider = context.Load <IServiceProvider>();

                SomethingDisposable somethingDisposable;

                using (var scope = serviceProvider.CreateScope())
                {
                    context.Save(scope);

                    somethingDisposable = scope.ServiceProvider.GetRequiredService <SomethingDisposable>();

                    Assert.That(somethingDisposable.HasBeenDisposed, Is.False);

                    var somethingDisposableResolvedAgain = scope.ServiceProvider.GetRequiredService <SomethingDisposable>();

                    Assert.That(somethingDisposableResolvedAgain, Is.SameAs(somethingDisposable));

                    await next();

                    var somethingDisposableInjectedIntoMessageHandler = context.Load <SomethingDisposable>();

                    Assert.That(somethingDisposableInjectedIntoMessageHandler, Is.SameAs(somethingDisposable));

                    Assert.That(somethingDisposable.HasBeenDisposed, Is.False);
                }

                Assert.That(somethingDisposable.HasBeenDisposed, Is.True);
            }
コード例 #15
0
        /// <summary>
        /// Invoke the receive side of the default
        /// pipeline with the passed message
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="id"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        private static async Task Invoke(
            IServiceProvider provider,
            string id,
            object message
            )
        {
            var context = new FakeTransactionContext();

            var msg = new Message(
                new Dictionary <string, string>()
            {
                { Headers.MessageId, id }
            },
                message
                );

            var serializer = provider.GetService <ISerializer>();
            var invoker    = provider.GetService <IPipelineInvoker>();

            AmbientTransactionContext.SetCurrent(context);

            var transportMessage = await serializer.Serialize(msg);

            var ctx = new IncomingStepContext(transportMessage, context);

            await invoker.Invoke(ctx);

            context.Dispose();
        }
コード例 #16
0
        public async Task ComparePerf(ThingToCheck whatToCheck)
        {
            await Task.FromResult(false);

            var iterations = 100000;
            var pipeline   = CreateFakePipeline(10).ToArray();
            var invoker    = GetInvoker(whatToCheck, pipeline);

            var stopwatch = Stopwatch.StartNew();

            for (var counter = 0; counter < iterations; counter++)
            {
                var headers          = new Dictionary <string, string>();
                var body             = new byte[] { 1, 2, 3 };
                var transportMessage = new TransportMessage(headers, body);
                var trannieContext   = new TransactionContext();
                var stepContext      = new IncomingStepContext(transportMessage, trannieContext);

                await invoker.Invoke(stepContext);
            }

            var elapsed = stopwatch.Elapsed;

            Console.WriteLine($"{iterations} iterations took {elapsed.TotalSeconds:0.0} s - that's {iterations / elapsed.TotalSeconds:0.0} iterations/s");
        }
コード例 #17
0
        public void CanMeasureTimeSpentInSteps()
        {
            var stats    = new PipelineStepProfilerStats();
            var pipeline = new DefaultPipeline()
                           .OnReceive(new Step300())
                           .OnReceive(new Step100())
                           .OnReceive(new Step200());

            var profiler = new PipelineStepProfiler(pipeline, stats);

            var receivePipeline  = profiler.ReceivePipeline();
            var invoker          = new DefaultPipelineInvoker();
            var transportMessage = new TransportMessage(new Dictionary <string, string>(), new byte[0]);

            using (new DefaultTransactionContextScope())
            {
                var stepContext = new IncomingStepContext(transportMessage, AmbientTransactionContext.Current);

                invoker.Invoke(stepContext, receivePipeline).Wait();

                var stepStats = stats.GetStats();

                Console.WriteLine(string.Join(Environment.NewLine, stepStats));
            }
        }
コード例 #18
0
        private static Activity StartActivity(IncomingStepContext context)
        {
            var message = context.Load <Message>();
            var headers = message.Headers;

            var activity = new Activity(TracingConstants.ConsumerActivityName);

            if (headers.TryGetValue(TracingConstants.TraceParentHeaderName, out var requestId) == false)
            {
                headers.TryGetValue(TracingConstants.RequestIdHeaderName, out requestId);
            }

            if (string.IsNullOrEmpty(requestId) == false)
            {
                // This is the magic
                activity.SetParentId(requestId);

                if (headers.TryGetValue(TracingConstants.TraceStateHeaderName, out var traceState))
                {
                    activity.TraceStateString = traceState;
                }
            }

            // The current activity gets an ID with the W3C format
            activity.Start();

            return(activity);
        }
コード例 #19
0
        /// <summary>
        /// Executes the entire message processing pipeline in an exception handler, tracking the number of failed delivery attempts.
        /// Forwards the message to the error queue when the max number of delivery attempts has been exceeded.
        /// </summary>
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var transportMessage   = context.Load <TransportMessage>() ?? throw new RebusApplicationException("Could not find a transport message in the current incoming step context");
            var transactionContext = context.Load <ITransactionContext>() ?? throw new RebusApplicationException("Could not find a transaction context in the current incoming step context");

            var messageId = transportMessage.Headers.GetValueOrNull(Headers.MessageId);

            if (string.IsNullOrWhiteSpace(messageId))
            {
                await _moveMessageToErrorQueue(context, transactionContext,
                                               new RebusApplicationException($"Received message with empty or absent '{Headers.MessageId}' header! All messages must be" +
                                                                             " supplied with an ID . If no ID is present, the message cannot be tracked" +
                                                                             " between delivery attempts, and other stuff would also be much harder to" +
                                                                             " do - therefore, it is a requirement that messages be supplied with an ID."));

                return;
            }

            _checkFinal(context, true);

            if (_errorTracker.HasFailedTooManyTimes(messageId))
            {
                await _handleError(context, next, messageId);
            }
            else
            {
                await _handle(context, next, messageId, transactionContext, messageId);
            }
        }
コード例 #20
0
        async Task _handle(IncomingStepContext context, Func <Task> next, string identifierToTrackMessageBy, ITransactionContext transactionContext, string messageId, string secondLevelMessageId = null)
        {
            try
            {
                await next();

                await transactionContext.Commit();

                _errorTracker.CleanUp(messageId);

                if (secondLevelMessageId != null)
                {
                    _errorTracker.CleanUp(secondLevelMessageId);
                }
            }
            catch (OperationCanceledException) when(_cancellationToken.IsCancellationRequested)
            {
                _logger.Info("Dispatch of message with ID {messageId} was cancelled", messageId);

                transactionContext.Abort();
            }
            catch (Exception exception)
            {
                _errorTracker.RegisterError(identifierToTrackMessageBy, exception);
                _checkFinal(context);

                await _handleError(context, next, identifierToTrackMessageBy);
            }
        }
コード例 #21
0
 /// <summary>
 /// Deserializes the incoming message by invoking the currently configured <see cref="ISerializer"/> on the <see cref="TransportMessage"/> found in the context,
 /// storing the result as the <see cref="Message"/> returned by the serializer
 /// </summary>
 public async Task Process(IncomingStepContext context, Func<Task> next)
 {
     var transportMessage = context.Load<TransportMessage>();
     var message = await _serializer.Deserialize(transportMessage);
     context.Save(message);
     await next();
 }
コード例 #22
0
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var message = context.Load <Message>();
            var headers = message.Headers;

            if (headers.ContainsKey(MapLegacyHeadersIncomingStep.LegacyMessageHeader))
            {
                var body  = message.Body;
                var array = body as object[];

                if (array == null)
                {
                    throw new FormatException(
                              $"Incoming message has the '{MapLegacyHeadersIncomingStep.LegacyMessageHeader}' header, but the message body {body} is not an object[] as expected");
                }

                foreach (var bodyToDispatch in array)
                {
                    var messageBodyToDispatch = PossiblyConvertBody(bodyToDispatch, headers);

                    context.Save(new Message(headers, messageBodyToDispatch));

                    await next();
                }

                return;
            }

            await next();
        }
コード例 #23
0
        /// <summary>
        /// Check if the current message handling is 'done' and flag MessageId as FINAL.
        /// Support also 2nd-level retries and FailFast.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="beforeTry">true if the check is prior to handling, to bailout before event try.</param>
        /// <remarks>
        /// At the start of the Handling we want to bailout if the current DeliveryCount is greater than the threashold.
        /// DeliveryCount is natively 1-based: first try has count=1 before trying.
        /// When this is the last try we need first to execute.
        /// </remarks>
        private void _checkFinal(IncomingStepContext context, bool beforeTry = false)
        {
            var transportMessage = context.Load <TransportMessage>();
            var messageId        = transportMessage.Headers.GetValue(Headers.MessageId);

            int?transportDeliveryCount = null;

            if (transportMessage.Headers.TryGetValue(DeliveryCountHeader, out var dch) &&
                int.TryParse(dch, out var dc))
            {
                transportDeliveryCount = dc;
            }

            _checkFinal(messageId, transportDeliveryCount, beforeTry);

            if (_arkRetryStrategySettings.SecondLevelRetriesEnabled)
            {
                var secondLevelMessageId = GetSecondLevelMessageId(messageId);

                if (transportDeliveryCount != null)
                {
                    // can happen that we have fail-fasted the first-level and we're failing the 2nd-level
                    transportDeliveryCount -= _arkRetryStrategySettings.MaxDeliveryAttempts;
                    if (transportDeliveryCount <= 0)
                    {
                        transportDeliveryCount = 1;
                    }
                }

                _checkFinal(secondLevelMessageId, transportDeliveryCount, beforeTry);
            }
        }
コード例 #24
0
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var messageContext = MessageContext.Current;

            var messagesTypeName = messageContext.Message.Body.GetType().Name;

            const string transactionName = nameof(transactionName);

            NewRelic.SetTransactionName(transactionName, $"{messagesTypeName}");

            foreach (var messageContextHeader in messageContext.Headers)
            {
                NewRelic.AddCustomParameter(messageContextHeader.Key, messageContextHeader.Value);
            }

            Stopwatch stopwatch = Stopwatch.StartNew();

            try
            {
                await next();
            }
            catch (Exception error)
            {
                NewRelic.NoticeError(error, messageContext.Headers);
                throw;
            }
            finally
            {
                stopwatch.Stop();
                NewRelic.RecordResponseTimeMetric($"{messagesTypeName}",
                                                  stopwatch.ElapsedMilliseconds);
            }
        }
コード例 #25
0
        /// <summary>
        /// Checks to see if the incoming message has the <see cref="Headers.DeferredUntil"/> header. If that is the case, the message is either stored for later delivery
        /// or forwarded to the configured external timeout manager. If not, the message will be passed on down the pipeline.
        /// </summary>
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var transportMessage = context.Load <TransportMessage>();

            var headers = transportMessage.Headers;

            if (!headers.TryGetValue(Headers.DeferredUntil, out var deferredUntil))
            {
                await next();

                //return;don't return here! for some reason it is faster to have an "else"
            }
            else
            {
                if (!headers.ContainsKey(Headers.DeferredRecipient))
                {
                    throw new RebusApplicationException(
                              $"Received message {headers[Headers.MessageId]} with the '{Headers.DeferredUntil}' header" +
                              $" set to '{headers[Headers.DeferredUntil]}', but the message had no" +
                              $" '{Headers.DeferredRecipient}' header!");
                }

                if (UsingExternalTimeoutManager)
                {
                    var transactionContext = context.Load <ITransactionContext>();

                    await ForwardMessageToExternalTimeoutManager(transportMessage, transactionContext);
                }
                else
                {
                    await StoreMessageUntilDue(deferredUntil, headers, transportMessage);
                }
            }
        }
コード例 #26
0
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var items = context.Load <ITransactionContext>().Items;

            if (!items.TryGetValue(CurrentTransactionContextKey, out var temp))
            {
                await next();

                return;
            }

            if (!(temp is Transaction transaction))
            {
                await next();

                return;
            }

            using (var scope = new TransactionScope(transaction, TransactionScopeAsyncFlowOption.Enabled))
            {
                await next();

                scope.Complete();
            }
        }
コード例 #27
0
ファイル: TplWorker.cs プロジェクト: xiaguoli/Rebus
        async Task ProcessMessage(TransactionContext context, TransportMessage transportMessage)
        {
            try
            {
                AmbientTransactionContext.SetCurrent(context);

                var stepContext = new IncomingStepContext(transportMessage, context);
                await _pipelineInvoker.Invoke(stepContext);

                try
                {
                    await context.Complete();
                }
                catch (Exception exception)
                {
                    _log.Error(exception, "An error occurred when attempting to complete the transaction context");
                }
            }
            catch (OperationCanceledException exception)
            {
                context.Abort();

                _log.Error(exception, "Worker was aborted while handling message {messageLabel}", transportMessage.GetMessageLabel());
            }
            catch (Exception exception)
            {
                context.Abort();

                _log.Error(exception, "Unhandled exception while handling message {messageLabel}", transportMessage.GetMessageLabel());
            }
            finally
            {
                AmbientTransactionContext.SetCurrent(null);
            }
        }
コード例 #28
0
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            await next().ConfigureAwait(false);

            var message         = context.Load <Message>();
            var handlerInvokers = context.Load <HandlerInvokers>();

            var createdAndUpdatedSagaData = handlerInvokers
                                            .Where(i => i.HasSaga)
                                            .Select(i => new
            {
                i.Handler,
                SagaData = i.GetSagaData()
            })
                                            .Where(a => a.SagaData != null)
                                            .ToList();

            var saveTasks = createdAndUpdatedSagaData
                            .Select(sagaData =>
            {
                var metadata = GetMetadata(sagaData.SagaData, sagaData.Handler, message);

                return(_sagaSnapshotStorage.Save(sagaData.SagaData, metadata));
            });

            await Task.WhenAll(saveTasks).ConfigureAwait(false);
        }
        public async Task WrapsInvokersSoTheyCanRunInsideAnActivity()
        {
            var step = new IncomingDiagnosticsHandlerInvokerWrapper();

            var headers = new Dictionary <string, string>
            {
                { Headers.Type, "MyType" }
            };
            var transportMessage = new TransportMessage(headers, Array.Empty <byte>());
            var message          = new Message(headers, Array.Empty <byte>());

            var innerInvoker = new TestInvoker(() => { });

            var handlerInvokers = new HandlerInvokers(message, new[] { innerInvoker });

            var scope   = new RebusTransactionScope();
            var context = new IncomingStepContext(transportMessage, scope.TransactionContext);

            context.Save(handlerInvokers);

            var callbackWasInvoked = false;
            await step.Process(context, () =>
            {
                callbackWasInvoked = true;
                return(Task.CompletedTask);
            });

            Assert.That(callbackWasInvoked);

            var updatedInvokers = context.Load <HandlerInvokers>();

            Assert.That(updatedInvokers, Is.Not.SameAs(handlerInvokers));
            Assert.That(updatedInvokers, Has.Exactly(1).Items.And.All.TypeOf <HandlerInvokerWrapper>());
        }
コード例 #30
0
        /// <summary>
        /// Processes the message
        /// </summary>
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            var invokers         = context.Load <HandlerInvokers>();
            var didInvokeHandler = false;

            foreach (var invoker in invokers)
            {
                await invoker.Invoke();

                didInvokeHandler = true;
            }

            if (!didInvokeHandler)
            {
                var message = context.Load <Message>();

                var messageId   = message.GetMessageId();
                var messageType = message.GetMessageType();

                var text = string.Format("Message with ID {0} and type {1} could not be dispatched to any handlers",
                                         messageId, messageType);

                throw new RebusApplicationException(text);
            }

            await next();
        }
コード例 #31
0
        public async Task Given_incoming_step_context_has_sequence_it_should_increment(int?incomingSequenceNr, int expectedOutgoingSequenceNr)
        {
            var incomingHeaders = new Dictionary <string, string>();

            if (incomingSequenceNr.HasValue)
            {
                incomingHeaders.Add(Headers.CorrelationSequence, incomingSequenceNr.ToString());
            }
            var incomingStepContext = new IncomingStepContext(
                new TransportMessage(
                    incomingHeaders, new byte[0]),
                _transactionContextMock.Object
                );

            incomingStepContext.Save(new Message(incomingHeaders, new { }));
            _stepContext.Save(incomingStepContext);

            // Act
            await _sut.Process(_stepContext, _next);

            // Assert
            _messageHeaders
            .Should().ContainKey(Headers.CorrelationSequence)
            .WhichValue
            .Should().Be(expectedOutgoingSequenceNr.ToString());
        }
コード例 #32
0
ファイル: Program.cs プロジェクト: EraYaN/ServiceBusTests
        public async Task Process(IncomingStepContext context, Func <Task> next)
        {
            // Message about to be processed. Log details of it to some kind of monitoring system, perf counters, etc
            try
            {
                if (_stats.ContainsKey(_address))
                {
                    _stats[_address]--;
                }
                else
                {
                    _stats[_address] = 0;
                }

                if (_stats[_address] < 0)
                {
                    _stats[_address] = 0;
                }
                await next();

                // Message succeeded.
            }
            catch (Exception ex)
            {
                // Log failure to monitoring but still throw so Rebus can retry
                throw;
            }
        }
コード例 #33
0
ファイル: FlowCorrelationIdStep.cs プロジェクト: nls75/Rebus
        static string GetCorrelationIdToAssign(IncomingStepContext incomingStepContext, Message outgoingMessage)
        {
            // if we're handling an incoming message right now, let either current correlation ID or the message ID flow
            if (incomingStepContext == null)
            {
                return outgoingMessage.Headers.GetValue(Headers.MessageId);
            }
            
            var incomingMessage = incomingStepContext.Load<Message>();

            var correlationId = incomingMessage.Headers.GetValueOrNull(Headers.CorrelationId)
                                ?? incomingMessage.Headers.GetValue(Headers.MessageId);

            return correlationId;
        }
コード例 #34
0
        static CorrelationInfo GetCorrelationIdToAssign(IncomingStepContext incomingStepContext, Message outgoingMessage)
        {
            // if we're handling an incoming message right now, let either current correlation ID or the message ID flow
            if (incomingStepContext == null)
            {
                var messageId = outgoingMessage.Headers.GetValue(Headers.MessageId);

                return new CorrelationInfo(messageId, 0);
            }

            var incomingMessage = incomingStepContext.Load<Message>();

            var correlationId = incomingMessage.Headers.GetValueOrNull(Headers.CorrelationId)
                                ?? incomingMessage.Headers.GetValue(Headers.MessageId);

            var correlationSequenceHeader = incomingMessage.Headers.GetValueOrNull(Headers.CorrelationSequence) ?? "0";
            var currentCorrelationSequence = ParseOrZero(correlationSequenceHeader);
            var nextCorrelationSequence = currentCorrelationSequence + 1;

            return new CorrelationInfo(correlationId, nextCorrelationSequence);
        }
コード例 #35
0
        /// <summary>
        /// Processes the message
        /// </summary>
        public async Task Process(IncomingStepContext context, Func<Task> next)
        {
            var invokers = context.Load<HandlerInvokers>();
            var didInvokeHandler = false;

            // if dispatch has already been aborted (e.g. in a transport message filter or something else that
            // was run before us....) bail out here:
            if (context.Load<bool>(AbortDispatchContextKey))
            {
                await next();
                return;
            }

            foreach (var invoker in invokers)
            {
                await invoker.Invoke();
                didInvokeHandler = true;

                // if dispatch was aborted at this point, bail out
                if (context.Load<bool>(AbortDispatchContextKey)) break;
            }

            // throw error if we should have executed a handler but we didn't
            if (!didInvokeHandler)
            {
                var message = context.Load<Message>();
                
                var messageId = message.GetMessageId();
                var messageType = message.GetMessageType();

                var text = string.Format("Message with ID {0} and type {1} could not be dispatched to any handlers",
                    messageId, messageType);

                throw new RebusApplicationException(text);
            }

            await next();
        }
コード例 #36
0
        /// <summary>
        /// Checks to see if the incoming message has the <see cref="Headers.DeferredUntil"/> header. If that is the case, the message is either stored for later delivery
        /// or forwarded to the configured external timeout manager. If not, the message will be passed on down the pipeline.
        /// </summary>
        public async Task Process(IncomingStepContext context, Func<Task> next)
        {
            var transportMessage = context.Load<TransportMessage>();

            string deferredUntil;

            var headers = transportMessage.Headers;

            if (!headers.TryGetValue(Headers.DeferredUntil, out deferredUntil))
            {
                await next();
                //return;don't return here! for some reason it is faster to have an "else"
            }
            else
            {
                if (!headers.ContainsKey(Headers.DeferredRecipient))
                {
                    throw new ApplicationException(
                        $"Received message {headers[Headers.MessageId]} with the '{Headers.DeferredUntil}' header" +
                        $" set to '{headers[Headers.DeferredUntil]}', but the message had no" +
                        $" '{Headers.DeferredRecipient}' header!");
                }

                if (UsingExternalTimeoutManager)
                {
                    var transactionContext = context.Load<ITransactionContext>();

                    await ForwardMessageToExternalTimeoutManager(transportMessage, transactionContext);
                }
                else
                {
                    await StoreMessageUntilDue(deferredUntil, headers, transportMessage);
                }
            }
        }
コード例 #37
0
        public async Task Process(IncomingStepContext context, Func<Task> next)
        {
            var transportMessage = context.Load<TransportMessage>();

            string deferredUntil;

            var headers = transportMessage.Headers;

            if (!headers.TryGetValue(Headers.DeferredUntil, out deferredUntil))
            {
                await next();
                return;
            }

            if (!headers.ContainsKey(Headers.ReturnAddress))
            {
                throw new ApplicationException(string.Format("Received message {0} with the '{1}' header set to '{2}', but the message had no '{3}' header!",
                    headers[Headers.MessageId],
                    Headers.DeferredUntil,
                    headers[Headers.DeferredUntil],
                    Headers.ReturnAddress));
            }

            DateTimeOffset approximateDueTime;
            if (!DateTimeOffset.TryParseExact(deferredUntil, DateTimeOffsetFormat, CultureInfo.InvariantCulture,
                    DateTimeStyles.RoundtripKind, out approximateDueTime))
            {
                throw new FormatException(string.Format("Could not parse the '{0}' header value '{1}' into a valid DateTimeOffset!",
                    Headers.DeferredUntil, deferredUntil));
            }

            _log.Info("Deferring message {0} until {1}", headers[Headers.MessageId], approximateDueTime);

            headers.Remove(Headers.DeferredUntil);

            await _timeoutManager.Defer(approximateDueTime, headers, transportMessage.Body);
        }
コード例 #38
0
ファイル: LoadSagaDataStep.cs プロジェクト: mhertis/Rebus
        public async Task Process(IncomingStepContext context, Func<Task> next)
        {
            var handlerInvokersForSagas = context.Load<HandlerInvokers>()
                .Where(l => l.HasSaga)
                .ToList();

            var message = context.Load<Message>();
            var label = message.GetMessageLabel();

            var body = message.Body;
            var loadedSagaData = new List<RelevantSagaInfo>();
            var newlyCreatedSagaData = new List<RelevantSagaInfo>();

            foreach (var sagaInvoker in handlerInvokersForSagas)
            {
                var foundExistingSagaData = false;

                var correlationProperties = _sagaHelper.GetCorrelationProperties(body, sagaInvoker.Saga);
                var correlationPropertiesRelevantForMessage = correlationProperties.ForMessage(body);

                foreach (var correlationProperty in correlationPropertiesRelevantForMessage)
                {
                    var valueFromMessage = correlationProperty.ValueFromMessage(body);
                    var sagaData = await _sagaStorage.Find(sagaInvoker.Saga.GetSagaDataType(), correlationProperty.PropertyName, valueFromMessage);

                    if (sagaData == null) continue;

                    sagaInvoker.SetSagaData(sagaData);
                    foundExistingSagaData = true;
                    loadedSagaData.Add(new RelevantSagaInfo(sagaData, correlationProperties, sagaInvoker.Saga));

                    _log.Debug("Found existing saga data with ID {0} for message {1}", sagaData.Id, label);
                    break;
                }

                if (!foundExistingSagaData)
                {
                    var messageType = body.GetType();
                    var canBeInitiatedByThisMessageType = sagaInvoker.CanBeInitiatedBy(messageType);

                    if (canBeInitiatedByThisMessageType)
                    {
                        var newSagaData = _sagaHelper.CreateNewSagaData(sagaInvoker.Saga);
                        sagaInvoker.SetSagaData(newSagaData);
                        _log.Debug("Created new saga data with ID {0} for message {1}", newSagaData.Id, label);
                        newlyCreatedSagaData.Add(new RelevantSagaInfo(newSagaData, correlationProperties, sagaInvoker.Saga));
                    }
                    else
                    {
                        _log.Debug("Could not find existing saga data for message {0}", label);
                        sagaInvoker.SkipInvocation();
                    }
                }
            }

            await next();

            var newlyCreatedSagaDataToSave = newlyCreatedSagaData.Where(s => !s.Saga.WasMarkedAsComplete);
            var loadedSagaDataToUpdate = loadedSagaData.Where(s => !s.Saga.WasMarkedAsComplete);
            var loadedSagaDataToDelete = loadedSagaData.Where(s => s.Saga.WasMarkedAsComplete);

            foreach (var sagaDataToInsert in newlyCreatedSagaDataToSave)
            {
                await _sagaStorage.Insert(sagaDataToInsert.SagaData, sagaDataToInsert.CorrelationProperties);
            }

            foreach (var sagaDataToUpdate in loadedSagaDataToUpdate)
            {
                await _sagaStorage.Update(sagaDataToUpdate.SagaData, sagaDataToUpdate.CorrelationProperties);
            }

            foreach (var sagaDataToUpdate in loadedSagaDataToDelete)
            {
                await _sagaStorage.Delete(sagaDataToUpdate.SagaData);
            }
        }
コード例 #39
0
        public async Task Process(IncomingStepContext context, Func<Task> next)
        {
            var transportMessage = context.Load<TransportMessage>();

            string deferredUntil;

            var headers = transportMessage.Headers;

            if (!headers.TryGetValue(Headers.DeferredUntil, out deferredUntil))
            {
                await next();
                return;
            }

            if (!headers.ContainsKey(Headers.ReturnAddress))
            {
                throw new ApplicationException(string.Format("Received message {0} with the '{1}' header set to '{2}', but the message had no '{3}' header!",
                    headers[Headers.MessageId],
                    Headers.DeferredUntil,
                    headers[Headers.DeferredUntil],
                    Headers.ReturnAddress));
            }

            if (UsingExternalTimeoutManager)
            {
                var transactionContext = context.Load<ITransactionContext>();

                await ForwardMessageToExternalTimeoutManager(transportMessage, transactionContext);
            }
            else
            {
                await StoreMessageUntilDue(deferredUntil, headers, transportMessage);
            }
        }