public Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, ContextBag context)
        {
            InMemoryTransaction inMemoryTransaction = null;

            if (transaction.TryGet(out inMemoryTransaction))
            {
            }

            foreach (var unicastTransportOperation in outgoingMessages.UnicastTransportOperations)
            {
                if (inMemoryTransaction != null && unicastTransportOperation.RequiredDispatchConsistency != DispatchConsistency.Isolated)
                {
                    var x = unicastTransportOperation;
                    inMemoryTransaction.Enlist(() => DispatchUnicastMessage(x));
                }
                else
                {
                    DispatchUnicastMessage(unicastTransportOperation);
                }
            }

            foreach (var multicastTransportOperation in outgoingMessages.MulticastTransportOperations)
            {
                if (inMemoryTransaction != null && multicastTransportOperation.RequiredDispatchConsistency != DispatchConsistency.Isolated)
                {
                    inMemoryTransaction.Enlist(() => DispatchMulticastMessage(multicastTransportOperation));
                }
                else
                {
                    DispatchMulticastMessage(multicastTransportOperation);
                }
            }

            return(Task.CompletedTask);
        }
        private async Task HandleError(
            byte[] messageBody,
            int retryAttempt,
            Exception exception,
            Dictionary <string, string> headers,
            string messageId)
        {
            var transportTransaction = new TransportTransaction();
            InMemoryTransaction errorHandlingTransaction = null;

            if (this.pushSettings.RequiredTransactionMode == TransportTransactionMode.SendsAtomicWithReceive)
            {
                transportTransaction.Set(errorHandlingTransaction = new InMemoryTransaction());
            }

            try
            {
                var immediateProcessingFailures = ++retryAttempt;
                var handleResult = await onError(new ErrorContext(
                                                     exception,
                                                     headers,
                                                     messageId,
                                                     messageBody,
                                                     transportTransaction,
                                                     immediateProcessingFailures));

                if (handleResult == ErrorHandleResult.RetryRequired)
                {
                    await PushInternal(messageBody, messageId, headers, immediateProcessingFailures);
                }
                else
                {
                    errorHandlingTransaction?.Complete();
                }
            }
            catch (Exception e)
            {
                criticalError.Raise("Exception while handling pipeline error.", e);
                await HandleError(messageBody, ++retryAttempt, exception, headers, messageId);
            }
        }
        private async Task PushInternal(byte[] messageBody, string messageId, Dictionary <string, string> headers, int retryAttempt)
        {
            var transportTransaction = new TransportTransaction();
            InMemoryTransaction inMemoryTransaction = null;

            if (this.pushSettings.RequiredTransactionMode == TransportTransactionMode.SendsAtomicWithReceive)
            {
                transportTransaction.Set(inMemoryTransaction = new InMemoryTransaction());
            }

            messageId = messageId ?? Guid.NewGuid().ToString();
            headers   = headers ?? new Dictionary <string, string>();
            var contextBag = new ContextBag();
            var receiveCancellationTokenSource = new CancellationTokenSource();
            var messageContext = new MessageContext(
                messageId,
                headers,
                messageBody,
                transportTransaction,
                receiveCancellationTokenSource,
                contextBag);

            try
            {
                await onMessage(messageContext);

                if (receiveCancellationTokenSource.IsCancellationRequested)
                {
                    await PushInternal(messageBody, messageId, headers, retryAttempt);
                }

                inMemoryTransaction?.Complete();
            }
            catch (Exception e)
            {
                await HandleError(messageBody, retryAttempt, e, headers, messageId);
            }
        }