コード例 #1
0
ファイル: TestSendAndReceive.cs プロジェクト: rasmuskl/Rebus
        public void CanSendAndReceiveMessageWithHeaders()
        {
            // arrange
            var encoding = Encoding.UTF7;
            var transportMessageToSend = new TransportMessageToSend
            {
                Body    = encoding.GetBytes("this is some data"),
                Headers = new Dictionary <string, object>
                {
                    { "key1", "value1" },
                    { "key2", "value2" },
                }
            };

            // act
            sender.Send(receiver.InputQueue, transportMessageToSend, new NoTransaction());
            Thread.Sleep(MaximumExpectedQueueLatency);
            var receivedTransportMessage = receiver.ReceiveMessage(new NoTransaction());

            // assert
            encoding.GetString(receivedTransportMessage.Body).ShouldBe("this is some data");
            var headers = receivedTransportMessage.Headers;

            headers.ShouldNotBe(null);
            headers.Count.ShouldBe(2);

            headers.ShouldContainKeyAndValue("key1", "value1");
            headers.ShouldContainKeyAndValue("key2", "value2");

            5.Times(() => receiver.ReceiveMessage(new NoTransaction()).ShouldBe(null));
        }
コード例 #2
0
        public void CanReceiveAndDoMultipleSendsAtomically(bool commitTransactionAndExpectMessagesToBeThere)
        {
            sender.Send(receiver.InputQueueAddress, MessageWith("hello"));

            var destination1 = factory.CreateReceiver("destination1");
            var destination2 = factory.CreateReceiver("destination2");

            Thread.Sleep(300);

            // pretend that this is a message handler tx scope...
            using (var tx = new TransactionScope())
            {
                // arrange
                var receivedTransportMessage = receiver.ReceiveMessage();

                // act
                sender.Send(destination1.InputQueueAddress, receivedTransportMessage.ToForwardableMessage());
                sender.Send(destination2.InputQueueAddress, receivedTransportMessage.ToForwardableMessage());

                if (commitTransactionAndExpectMessagesToBeThere)
                {
                    tx.Complete();
                }
            }

            Thread.Sleep(300);

            // assert
            var msg1 = destination1.ReceiveMessage();
            var msg2 = destination2.ReceiveMessage();

            if (commitTransactionAndExpectMessagesToBeThere)
            {
                msg1.ShouldNotBe(null);
                Encoding.GetString(msg1.Body).ShouldBe("hello");

                msg2.ShouldNotBe(null);
                Encoding.GetString(msg2.Body).ShouldBe("hello");

                receiver.ReceiveMessage().ShouldBe(null);
            }
            else
            {
                msg1.ShouldBe(null);
                msg2.ShouldBe(null);
                receiver.ReceiveMessage().ShouldNotBe(null);
            }
        }
コード例 #3
0
        /// <inheritdoc />
        public IReceivedMessageInternal ReceiveMessage(IMessageContext context)
        {
            //we can't attach the span since we don't have the parent until after we get a message
            //so save off the start and end times, and replace those in the child span below
            var start   = DateTime.UtcNow;
            var message = _handler.ReceiveMessage(context);
            var end     = DateTime.UtcNow;

            if (message == null)
            {
                return(null);
            }
            var activityContext = message.Extract(_tracer, _headers.StandardHeaders);

            //blocking operations can last forever for queues that can signal for new messages
            //so, we will treat this is a 0 ms operation, rather than have it possibly last for N
            if (IsBlockingOperation)
            {
                start = end;
            }

            using (var scope = _tracer.StartActivity("ReceiveMessage", ActivityKind.Internal, activityContext, startTime: start))
            {
                scope?.AddMessageIdTag(message);
                scope?.SetTag("IsBlockingOperation", IsBlockingOperation);
                scope?.SetEndTime(end);
                return(message);
            }
        }
コード例 #4
0
        /// <summary>
        /// Receives a <see cref="ReceivedTransportMessage"/> using the underlying implementation of <see cref="IReceiveMessages"/>
        /// decrypting the message body if necessary, and remove the additional encryption headers
        /// </summary>
        public ReceivedTransportMessage ReceiveMessage(ITransactionContext context)
        {
            var receivedTransportMessage = innerReceiveMessages.ReceiveMessage(context);

            if (receivedTransportMessage == null)
            {
                return(null);
            }

            byte[] body;
            var    headers = receivedTransportMessage.Headers.Clone();

            if (headers.ContainsKey(Headers.Encrypted))
            {
                var iv = receivedTransportMessage.GetStringHeader(Headers.EncryptionSalt);
                body = helper.Decrypt(receivedTransportMessage.Body, iv);

                headers.Remove(Headers.EncryptionSalt);
                headers.Remove(Headers.Encrypted);
            }
            else
            {
                body = receivedTransportMessage.Body;
            }

            return(new ReceivedTransportMessage
            {
                Id = receivedTransportMessage.Id,
                Headers = headers,
                Label = receivedTransportMessage.Label,
                Body = body,
            });
        }
コード例 #5
0
        /// <summary>
        /// Tries the process the new incoming message.
        /// </summary>
        /// <param name="context">The context.</param>
        private void DoTry(IMessageContext context)
        {
            var transportMessage = _receiveMessages.ReceiveMessage(context);

            if (transportMessage == null)
            {
                //delay processing since we have no messages to process
                if (!_idle)
                {
                    Idle(this, EventArgs.Empty);
                    _idle = true;
                }
                _noMessageToProcessBackOffHelper.Value.Wait();
                return;
            }

            //reset the back off counter - we have a message to process, so the wait times are now reset
            _noMessageToProcessBackOffHelper.Value.Reset();
            if (_idle)
            {
                NotIdle(this, EventArgs.Empty);
                _idle = false;
            }

            _processMessage.Handle(context, transportMessage);
        }
コード例 #6
0
        void DoWork(IReceiveMessages messageQueue)
        {
            try
            {
                using (var tx = new TransactionScope())
                {
                    var ctx = new AmbientTransactionContext();
                    var receivedTransportMessage = messageQueue.ReceiveMessage(ctx);

                    if (receivedTransportMessage == null)
                    {
                        return;
                    }

                    try
                    {
                        SendMessage(receivedTransportMessage);

                        tx.Complete();
                    }
                    catch (Exception e)
                    {
                        log.Error(e, "Could not send message {0} to destination URI {1} - waiting 1 sec before retrying",
                                  receivedTransportMessage.Id, destinationUri);

                        Thread.Sleep(TimeSpan.FromSeconds(1));
                    }
                }
            }
            catch (Exception e)
            {
                log.Error("Unhandled exception during receive operation", e);
            }
        }
コード例 #7
0
ファイル: OutboundService.cs プロジェクト: JanRou/Rebus
        void DoWork(IReceiveMessages messageQueue)
        {
            try
            {
                using (var tx = new TransactionScope())
                {
                    var ctx = new AmbientTransactionContext();
                    var receivedTransportMessage = messageQueue.ReceiveMessage(ctx);

                    if (receivedTransportMessage == null) return;

                    try
                    {
                        SendMessage(receivedTransportMessage);

                        tx.Complete();
                    }
                    catch (Exception e)
                    {
                        log.Error(e, "Could not send message {0} to destination URI {1} - waiting 1 sec before retrying",
                                  receivedTransportMessage.Id, destinationUri);

                        Thread.Sleep(TimeSpan.FromSeconds(1));
                    }
                }
            }
            catch (Exception e)
            {
                log.Error("Unhandled exception during receive operation", e);
            }
        }
コード例 #8
0
        void TryProcessIncomingMessage()
        {
            using (var transactionScope = BeginTransaction())
            {
                var transportMessage = receiveMessages.ReceiveMessage();

                if (transportMessage == null)
                {
                    Thread.Sleep(20);
                    return;
                }

                BeforeMessage();

                var id    = transportMessage.Id;
                var label = transportMessage.Label;

                if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id))
                {
                    log.Error("Handling message {0} has failed the maximum number of times", id);
                    MessageFailedMaxNumberOfTimes(transportMessage, errorTracker.GetErrorText(id));
                    errorTracker.StopTracking(id);
                    PoisonMessage();
                }
                else
                {
                    try
                    {
                        var message       = serializeMessages.Deserialize(transportMessage);
                        var returnAddress = message.GetHeader(Headers.ReturnAddress);

                        using (MessageContext.Enter(returnAddress))
                        {
                            foreach (var logicalMessage in message.Messages)
                            {
                                var typeToDispatch = logicalMessage.GetType();

                                log.Debug("Dispatching message {0}: {1}", id, typeToDispatch);

                                GetDispatchMethod(typeToDispatch).Invoke(this, new[] { logicalMessage });
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        log.Debug("Handling message {0} ({1}) has failed", label, id);
                        errorTracker.TrackDeliveryFail(id, exception);
                        AfterMessage(exception);
                        throw;
                    }
                }

                transactionScope.Complete();
                errorTracker.StopTracking(id);
                AfterMessage(null);
            }
        }
コード例 #9
0
        /// <summary>
        /// Receives a <see cref="ReceivedTransportMessage"/> using the underlying implementation of <see cref="IReceiveMessages"/>
        /// decrypting the message body if necessary, and remove the additional encryption headers
        /// </summary>
        public ReceivedTransportMessage ReceiveMessage(ITransactionContext context)
        {
            var message = innerReceiveMessages.ReceiveMessage(context);

            if (message == null)
            {
                return(null);
            }

            var clone = new ReceivedTransportMessage
            {
                Body    = message.Body,
                Headers = message.Headers.Clone(),
                Label   = message.Label,
                Id      = message.Id
            };

            var headers = clone.Headers;

            if (encryptionHelper != null)
            {
                if (headers.ContainsKey(Headers.Encrypted))
                {
                    var iv = clone.GetStringHeader(Headers.EncryptionSalt);
                    clone.Body = encryptionHelper.Decrypt(clone.Body, iv);

                    headers.Remove(Headers.EncryptionSalt);
                    headers.Remove(Headers.Encrypted);
                }
            }

            if (compressionHelper != null)
            {
                if (headers.ContainsKey(Headers.Compression))
                {
                    var compressionType = (headers[Headers.Compression] ?? "").ToString();

                    switch (compressionType)
                    {
                    case Headers.CompressionTypes.GZip:
                        clone.Body = compressionHelper.Decompress(clone.Body);
                        break;

                    default:
                        throw new ArgumentException(
                                  string.Format(
                                      "Received message has the {0} header, but the compression type is set to {1} which cannot be handled",
                                      Headers.Compression, compressionType));
                    }

                    headers.Remove(Headers.Compression);
                }
            }

            return(clone);
        }
コード例 #10
0
        /// <summary>
        /// Returns a message to process.
        /// </summary>
        /// <param name="context">The message context.</param>
        /// <returns>
        /// A message to process or null if there are no messages to process
        /// </returns>
        public IReceivedMessageInternal ReceiveMessage(IMessageContext context)
        {
            var result = _handler.ReceiveMessage(context);

            if (result != null)
            {
                ProcessResult(result);
            }
            return(result);
        }
コード例 #11
0
        /// <inheritdoc />
        public IReceivedMessageInternal ReceiveMessage(IMessageContext context)
        {
            IReceivedMessageInternal result = null;

            if (_policy == null)
            {
                _policies.Registry.TryGet(_policies.Definition.ReceiveMessageFromTransport, out _policy);
            }

            if (_policy != null)
            {
                _policy.Execute(() => result = _handler.ReceiveMessage(context));
            }
            else //no policy found
            {
                result = _handler.ReceiveMessage(context);
            }
            return(result);
        }
コード例 #12
0
ファイル: Program.cs プロジェクト: JanRou/Rebus
        static IEnumerable<ReceivedTransportMessage> GetAllTheMessages(IReceiveMessages messageQueue, ITransactionContext transactionContext)
        {
            var messages = new List<ReceivedTransportMessage>();
            ReceivedTransportMessage transportMessage;
            while ((transportMessage = messageQueue.ReceiveMessage(transactionContext)) != null)
            {
                messages.Add(transportMessage);
            }

            return messages;
        }
コード例 #13
0
        static IEnumerable <ReceivedTransportMessage> GetAllTheMessages(IReceiveMessages messageQueue, ITransactionContext transactionContext)
        {
            var messages = new List <ReceivedTransportMessage>();
            ReceivedTransportMessage transportMessage;

            while ((transportMessage = messageQueue.ReceiveMessage(transactionContext)) != null)
            {
                messages.Add(transportMessage);
            }

            return(messages);
        }
コード例 #14
0
        public void CanReceiveAndDoOneSingleSendAtomically(bool commitTransactionAndExpectMessagesToBeThere)
        {
            sender.Send(receiver.InputQueueAddress, MessageWith("hello"), new NoTransaction());

            var destination1 = factory.CreateReceiver("destination1");

            Thread.Sleep(300.Milliseconds());

            // pretend that this is a message handler tx scope...
            using (var tx = new TransactionScope())
            {
                var ctx = new AmbientTransactionContext();

                // arrange
                var receivedTransportMessage = receiver.ReceiveMessage(ctx);
                Assert.That(receivedTransportMessage, Is.Not.Null);

                // act
                sender.Send(destination1.InputQueueAddress, MessageWith("hello mr. 1"), ctx);

                if (commitTransactionAndExpectMessagesToBeThere)
                {
                    tx.Complete();
                }
            }

            Thread.Sleep(300.Milliseconds());

            // assert
            var msg1 = destination1.ReceiveMessage(new NoTransaction());

            if (commitTransactionAndExpectMessagesToBeThere)
            {
                Assert.That(msg1, Is.Not.Null);
                Assert.That(Encoding.GetString(msg1.Body), Is.EqualTo("hello mr. 1"));

                using (new TransactionScope())
                {
                    var ctx = new AmbientTransactionContext();
                    var receivedTransportMessage = receiver.ReceiveMessage(ctx);
                    Assert.That(receivedTransportMessage, Is.Null);
                }
            }
            else
            {
                Assert.That(msg1, Is.Null);

                using (new TransactionScope())
                {
                    var ctx = new AmbientTransactionContext();
                    var receivedTransportMessage = receiver.ReceiveMessage(ctx);
                    Assert.That(receivedTransportMessage, Is.Not.Null);
                    Assert.That(Encoding.GetString(receivedTransportMessage.Body), Is.EqualTo("hello"));
                }
            }
        }
コード例 #15
0
        public ReceivedTransportMessage ReceiveMessage()
        {
            var receivedTransportMessage = innerReceiveMessages.ReceiveMessage();

            var body = receivedTransportMessage.Headers.ContainsKey(Headers.Encrypted)
                           ? Decrypt(receivedTransportMessage.Body)
                           : receivedTransportMessage.Body;

            return(new ReceivedTransportMessage
            {
                Id = receivedTransportMessage.Id,
                Headers = receivedTransportMessage.Headers,
                Label = receivedTransportMessage.Label,
                Body = body,
            });
        }
コード例 #16
0
        /// <inheritdoc />
        public IReceivedMessageInternal ReceiveMessage(IMessageContext context)
        {
            //we can't attach the span since we don't have the parent until after we get a message
            //so save off the start and end times, and replace those in the child span below
            var start   = DateTime.UtcNow;
            var message = _handler.ReceiveMessage(context);
            var end     = DateTime.UtcNow;

            if (message == null)
            {
                return(null);
            }
            var spanContext = message.Extract(_tracer, _headers.StandardHeaders);

            //blocking operations can last forever for queues that can signal for new messages
            //so, we will treat this is a 0 ms operation, rather than have it possibly last for N
            if (IsBlockingOperation)
            {
                start = end;
            }

            if (spanContext != null)
            {
                using (IScope scope = _tracer.BuildSpan("ReceiveMessage").AddReference(References.FollowsFrom, spanContext).WithStartTimestamp(start)
                                      .StartActive(finishSpanOnDispose: true))
                {
                    scope.Span.AddMessageIdTag(message);
                    scope.Span.SetTag("IsBlockingOperation", IsBlockingOperation);
                    scope.Span.Finish(end);
                    return(message);
                }
            }

            using (IScope scope = _tracer.BuildSpan("ReceiveMessage").WithStartTimestamp(start).StartActive(finishSpanOnDispose: true))
            {
                scope.Span.AddMessageIdTag(message);
                scope.Span.SetTag("IsBlockingOperation", IsBlockingOperation);
                scope.Span.Finish(end);
                return(message);
            }
        }
コード例 #17
0
        void TryProcessIncomingMessage()
        {
            using (var transactionScope = BeginTransaction())
            {
                var transportMessage = receiveMessages.ReceiveMessage();

                if (transportMessage == null)
                {
                    Thread.Sleep(20);
                    return;
                }

                var id    = transportMessage.Id;
                var label = transportMessage.Label;

                MessageContext context = null;

                if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id))
                {
                    log.Error("Handling message {0} has failed the maximum number of times", id);
                    MessageFailedMaxNumberOfTimes(transportMessage, errorTracker.GetErrorText(id));
                    errorTracker.StopTracking(id);

                    try
                    {
                        PoisonMessage(transportMessage);
                    }
                    catch (Exception exceptionWhileRaisingEvent)
                    {
                        log.Error("An exception occurred while raising the PoisonMessage event: {0}",
                                  exceptionWhileRaisingEvent);
                    }
                }
                else
                {
                    try
                    {
                        BeforeTransportMessage(transportMessage);

                        var message = serializeMessages.Deserialize(transportMessage);

                        // successfully deserialized the transport message, let's enter a message context
                        context = MessageContext.Enter(message.Headers);

                        foreach (var logicalMessage in message.Messages)
                        {
                            context.SetLogicalMessage(logicalMessage);

                            try
                            {
                                BeforeMessage(logicalMessage);

                                var typeToDispatch = logicalMessage.GetType();

                                log.Debug("Dispatching message {0}: {1}", id, typeToDispatch);

                                GetDispatchMethod(typeToDispatch).Invoke(this, new[] { logicalMessage });

                                AfterMessage(null, logicalMessage);
                            }
                            catch (Exception exception)
                            {
                                try
                                {
                                    AfterMessage(exception, logicalMessage);
                                }
                                catch (Exception exceptionWhileRaisingEvent)
                                {
                                    log.Error("An exception occurred while raising the AfterMessage event, and an exception occurred some time before that as well. The first exception was this: {0}. And then, when raising the AfterMessage event (including the details of the first error), this exception occurred: {1}",
                                              exception, exceptionWhileRaisingEvent);
                                }
                                throw;
                            }
                            finally
                            {
                                context.ClearLogicalMessage();
                            }
                        }

                        AfterTransportMessage(null, transportMessage);
                    }
                    catch (Exception exception)
                    {
                        log.Debug("Handling message {0} ({1}) has failed", label, id);
                        try
                        {
                            AfterTransportMessage(exception, transportMessage);
                        }
                        catch (Exception exceptionWhileRaisingEvent)
                        {
                            log.Error("An exception occurred while raising the AfterTransportMessage event, and an exception occurred some time before that as well. The first exception was this: {0}. And then, when raising the AfterTransportMessage event (including the details of the first error), this exception occurred: {1}",
                                      exception, exceptionWhileRaisingEvent);
                        }
                        errorTracker.TrackDeliveryFail(id, exception);
                        if (context != null)
                        {
                            context.Dispose();                  //< dispose it if we entered
                        }
                        throw;
                    }
                }

                transactionScope.Complete();
                if (context != null)
                {
                    context.Dispose();                  //< dispose it if we entered
                }
                errorTracker.StopTracking(id);
            }
        }
コード例 #18
0
ファイル: Worker.cs プロジェクト: jlundstocholm/Rebus
        void DoTry()
        {
            var transportMessage = receiveMessages.ReceiveMessage(TransactionContext.Current);

            if (transportMessage == null)
            {
                // to back off and relax then there's no messages to process, we do this
                successiveNullMessagesReceived++;
                var sleepTimeIndex = Math.Min(nullMessageSleepTimes.Length - 1, successiveNullMessagesReceived);
                var timeToSleep    = nullMessageSleepTimes[sleepTimeIndex];
                Thread.Sleep(timeToSleep);
                return;
            }

            successiveNullMessagesReceived = 0;

            var id    = transportMessage.Id;
            var label = transportMessage.Label;

            MessageContext context = null;

            if (id == null)
            {
                HandlePoisonMessage(id, transportMessage);
                return;
            }

            if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id))
            {
                HandlePoisonMessage(id, transportMessage);
                errorTracker.StopTracking(id);
                return;
            }

            Exception transportMessageExceptionOrNull = null;

            try
            {
                BeforeTransportMessage(transportMessage);

                using (var scope = BeginTransaction())
                {
                    var message = serializeMessages.Deserialize(transportMessage);
                    // successfully deserialized the transport message, let's enter a message context
                    context = MessageContext.Establish(message.Headers);
                    MessageContextEstablished(context);

                    var unitsOfWork = unitOfWorkManagers.Select(u => u.Create())
                                      .Where(u => !ReferenceEquals(null, u))
                                      .ToArray(); //< remember to invoke the chain here :)

                    try
                    {
                        foreach (var logicalMessage in message.Messages.Select(MutateIncoming))
                        {
                            context.SetLogicalMessage(logicalMessage);

                            Exception logicalMessageExceptionOrNull = null;
                            try
                            {
                                BeforeMessage(logicalMessage);

                                var typeToDispatch = logicalMessage.GetType();

                                log.Debug("Dispatching message {0}: {1}", id, typeToDispatch);

                                GetDispatchMethod(typeToDispatch)
                                .Invoke(this, new[] { logicalMessage });
                            }
                            catch (Exception exception)
                            {
                                logicalMessageExceptionOrNull = exception;
                                throw;
                            }
                            finally
                            {
                                try
                                {
                                    AfterMessage(logicalMessageExceptionOrNull, logicalMessage);
                                }
                                catch (Exception exceptionWhileRaisingEvent)
                                {
                                    if (logicalMessageExceptionOrNull != null)
                                    {
                                        log.Error(
                                            "An exception occurred while raising the AfterMessage event, and an exception occurred some" +
                                            " time before that as well. The first exception was this: {0}. And then, when raising the" +
                                            " AfterMessage event (including the details of the first error), this exception occurred: {1}",
                                            logicalMessageExceptionOrNull, exceptionWhileRaisingEvent);
                                    }
                                    else
                                    {
                                        log.Error("An exception occurred while raising the AfterMessage event: {0}",
                                                  exceptionWhileRaisingEvent);
                                    }
                                }

                                context.ClearLogicalMessage();
                            }
                        }

                        foreach (var unitOfWork in unitsOfWork)
                        {
                            unitOfWork.Commit();
                        }
                    }
                    catch
                    {
                        foreach (var unitOfWork in unitsOfWork)
                        {
                            try
                            {
                                unitOfWork.Abort();
                            }
                            catch (Exception abortException)
                            {
                                log.Warn("An error occurred while aborting the unit of work {0}: {1}",
                                         unitOfWork, abortException);
                            }
                        }
                        throw;
                    }
                    finally
                    {
                        foreach (var unitOfWork in unitsOfWork)
                        {
                            unitOfWork.Dispose();
                        }
                    }

                    if (scope != null)
                    {
                        scope.Complete();
                    }
                }
            }
            catch (Exception exception)
            {
                transportMessageExceptionOrNull = exception;
                log.Debug("Handling message {0} ({1}) has failed", label, id);
                errorTracker.TrackDeliveryFail(id, exception);
                throw;
            }
            finally
            {
                try
                {
                    AfterTransportMessage(transportMessageExceptionOrNull, transportMessage);
                }
                catch (Exception exceptionWhileRaisingEvent)
                {
                    if (transportMessageExceptionOrNull != null)
                    {
                        log.Error(
                            "An exception occurred while raising the AfterTransportMessage event, and an exception occurred some" +
                            " time before that as well. The first exception was this: {0}. And then, when raising the" +
                            " AfterTransportMessage event (including the details of the first error), this exception occurred: {1}",
                            transportMessageExceptionOrNull, exceptionWhileRaisingEvent);
                    }
                    else
                    {
                        log.Error("An exception occurred while raising the AfterTransportMessage event: {0}", exceptionWhileRaisingEvent);
                    }
                }

                if (context != null)
                {
                    context.Dispose();                  //< dispose it if we entered
                }
            }

            errorTracker.StopTracking(id);
        }
コード例 #19
0
        void DoTry()
        {
            var transportMessage = receiveMessages.ReceiveMessage(TransactionContext.Current);

            if (transportMessage == null)
            {
                // to back off and relax when there's no messages to process, we do this
                nullMessageReceivedBackoffHelper.Wait();
                return;
            }

            nullMessageReceivedBackoffHelper.Reset();

            var id    = transportMessage.Id;
            var label = transportMessage.Label;

            MessageContext context = null;

            if (id == null)
            {
                HandlePoisonMessage(id, transportMessage);
                return;
            }

            if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id))
            {
                HandlePoisonMessage(id, transportMessage);
                errorTracker.StopTracking(id);
                return;
            }

            Exception transportMessageExceptionOrNull = null;

            try
            {
                BeforeTransportMessage(transportMessage);

                // Populate rebus-msg-id, if not set, from transport-level-id
                if (!transportMessage.Headers.ContainsKey(Headers.MessageId))
                {
                    transportMessage.Headers[Headers.MessageId] = transportMessage.Id;
                }

                using (var scope = BeginTransaction())
                {
                    var message = serializeMessages.Deserialize(transportMessage);
                    // successfully deserialized the transport message, let's enter a message context
                    context = MessageContext.Establish(message.Headers);
                    MessageContextEstablished(context);

                    var unitsOfWork = unitOfWorkManagers.Select(u => u.Create())
                                      .Where(u => !ReferenceEquals(null, u))
                                      .ToArray(); //< remember to invoke the chain here :)

                    try
                    {
                        foreach (var logicalMessage in message.Messages.Select(MutateIncoming))
                        {
                            context.SetLogicalMessage(logicalMessage);

                            Exception logicalMessageExceptionOrNull = null;
                            try
                            {
                                BeforeMessage(logicalMessage);

                                var typeToDispatch = logicalMessage.GetType();

                                messageLogger.LogReceive(id, logicalMessage);

                                try
                                {
                                    var dispatchMethod = GetDispatchMethod(typeToDispatch);
                                    var parameters     = new[] { logicalMessage };
                                    dispatchMethod.Invoke(this, parameters);
                                }
                                catch (TargetInvocationException tie)
                                {
                                    var exception = tie.InnerException;
                                    exception.PreserveStackTrace();
                                    throw exception;
                                }
                            }
                            catch (Exception exception)
                            {
                                logicalMessageExceptionOrNull = exception;
                                throw;
                            }
                            finally
                            {
                                try
                                {
                                    AfterMessage(logicalMessageExceptionOrNull, logicalMessage);
                                }
                                catch (Exception exceptionWhileRaisingEvent)
                                {
                                    if (logicalMessageExceptionOrNull != null)
                                    {
                                        log.Error(
                                            "An exception occurred while raising the AfterMessage event, and an exception occurred some" +
                                            " time before that as well. The first exception was this: {0}. And then, when raising the" +
                                            " AfterMessage event (including the details of the first error), this exception occurred: {1}",
                                            logicalMessageExceptionOrNull, exceptionWhileRaisingEvent);
                                    }
                                    else
                                    {
                                        log.Error("An exception occurred while raising the AfterMessage event: {0}",
                                                  exceptionWhileRaisingEvent);
                                    }
                                }

                                context.ClearLogicalMessage();
                            }
                        }

                        foreach (var unitOfWork in unitsOfWork)
                        {
                            try
                            {
                                unitOfWork.Commit();
                            }
                            catch (Exception exception)
                            {
                                throw new UnitOfWorkCommitException(exception, unitOfWork);
                            }
                        }
                    }
                    catch
                    {
                        foreach (var unitOfWork in unitsOfWork)
                        {
                            try
                            {
                                unitOfWork.Abort();
                            }
                            catch (Exception abortException)
                            {
                                log.Warn("An error occurred while aborting the unit of work {0}: {1}",
                                         unitOfWork, abortException);
                            }
                        }
                        throw;
                    }
                    finally
                    {
                        foreach (var unitOfWork in unitsOfWork)
                        {
                            unitOfWork.Dispose();
                        }
                    }

                    if (scope != null)
                    {
                        scope.Complete();
                    }
                }
            }
            catch (Exception exception)
            {
                transportMessageExceptionOrNull = exception;
                log.Debug("Handling message {0} with ID {1} has failed", label, id);
                errorTracker.TrackDeliveryFail(id, exception);
                throw new MessageHandleException(id, exception);
            }
            finally
            {
                try
                {
                    AfterTransportMessage(transportMessageExceptionOrNull, transportMessage);
                }
                catch (Exception exceptionWhileRaisingEvent)
                {
                    if (transportMessageExceptionOrNull != null)
                    {
                        log.Error(
                            "An exception occurred while raising the AfterTransportMessage event, and an exception occurred some" +
                            " time before that as well. The first exception was this: {0}. And then, when raising the" +
                            " AfterTransportMessage event (including the details of the first error), this exception occurred: {1}",
                            transportMessageExceptionOrNull, exceptionWhileRaisingEvent);
                    }
                    else
                    {
                        log.Error("An exception occurred while raising the AfterTransportMessage event: {0}", exceptionWhileRaisingEvent);
                    }
                }

                if (context != null)
                {
                    context.Dispose();                  //< dispose it if we entered
                }
            }

            errorTracker.StopTracking(id);
        }