Пример #1
0
        async Task DispatchAccordingToIsolationLevel(IList <Batch> outgoingBatches, BrokeredMessageReceiveContext receiveContext)
        {
            var batchesWithIsolatedDispatchConsistency = outgoingBatches.Where(t => t.RequiredDispatchConsistency == DispatchConsistency.Isolated);
            var batchesWithDefaultConsistency          = outgoingBatches.Where(t => t.RequiredDispatchConsistency == DispatchConsistency.Default).ToList();

            await routeOutgoingBatches.RouteBatches(batchesWithIsolatedDispatchConsistency, receiveContext, DispatchConsistency.Isolated).ConfigureAwait(false);

            await DispatchWithTransactionScopeIfRequired(batchesWithDefaultConsistency, receiveContext, DispatchConsistency.Default).ConfigureAwait(false);
        }
Пример #2
0
        Task DispatchBatches(IList <Batch> outgoingBatches, BrokeredMessageReceiveContext receiveContext)
        {
            // received brokered message has already been completed, so send everything out immediately
            if (receiveContext.ReceiveMode == ReceiveMode.ReceiveAndDelete)
            {
                return(routeOutgoingBatches.RouteBatches(outgoingBatches, receiveContext, DispatchConsistency.Default));
            }
            // default behavior is to postpone sends until complete (and potentially complete them as a single tx if possible)
            // but some messages may need to go out immediately

            return(DispatchAccordingToIsolationLevel(outgoingBatches, receiveContext));
        }
        Task <bool> HandleCompletion(BrokeredMessage message, BrokeredMessageReceiveContext context, bool canBeBatched, int slotNumber)
        {
            if (receiveMode == ReceiveMode.PeekLock)
            {
                if (canBeBatched)
                {
                    completion.Push(message.LockToken, slotNumber);
                }
                else
                {
                    return(context.IncomingBrokeredMessage.SafeCompleteAsync());
                }
            }

            return(TaskEx.CompletedTrue);
        }
        internal Task RouteBatch(Batch batch, BrokeredMessageReceiveContext context, DispatchConsistency consistency)
        {
            var outgoingBatches = batch.Operations;

            var passiveNamespaces = batch.Destinations.Namespaces.Where(n => n.Mode == NamespaceMode.Passive).ToList();
            var pendingSends      = new List <Task>();

            foreach (var entity in batch.Destinations.Entities.Where(entity => entity.Namespace.Mode == NamespaceMode.Active))
            {
                var routingOptions = GetRoutingOptions(context, consistency);

                if (!string.IsNullOrEmpty(routingOptions.ViaEntityPath))
                {
                    Logger.DebugFormat("Routing {0} messages to {1} via {2}", outgoingBatches.Count, entity.Path, routingOptions.ViaEntityPath);
                }
                else
                {
                    Logger.DebugFormat("Routing {0} messages to {1}", outgoingBatches.Count, entity.Path);
                }

                // don't use via on fallback, not supported across namespaces
                var fallbacks = passiveNamespaces.Select(n => senders.Get(entity.Path, null, n.Alias)).ToList();

                var ns = entity.Namespace;
                // only use via if the destination and via namespace are the same
                var via = routingOptions.SendVia && ns.ConnectionString == routingOptions.ViaConnectionString ? routingOptions.ViaEntityPath : null;
                var suppressTransaction = via == null;
                var messageSender       = senders.Get(entity.Path, via, ns.Alias);

                routingOptions.DestinationEntityPath = entity.Path;
                routingOptions.DestinationNamespace  = ns;

                var brokeredMessages = outgoingMessageConverter.Convert(outgoingBatches, routingOptions).ToList();

                pendingSends.Add(RouteOutBatchesWithFallbackAndLogExceptionsAsync(messageSender, fallbacks, brokeredMessages, suppressTransaction));
            }
            return(Task.WhenAll(pendingSends));
        }
Пример #5
0
        async Task DispatchWithTransactionScopeIfRequired(IList <Batch> toBeDispatchedOnComplete, BrokeredMessageReceiveContext context, DispatchConsistency consistency)
        {
            if (context.CancellationToken.IsCancellationRequested || !toBeDispatchedOnComplete.Any())
            {
                return;
            }

            await routeOutgoingBatches.RouteBatches(toBeDispatchedOnComplete, context, consistency).ConfigureAwait(false);
        }
        async Task ProcessMessage(IMessageReceiver internalReceiver, BrokeredMessage message, int slotNumber)
        {
            if (stopping)
            {
                logger.Info($"Received message with ID {message.MessageId} while shutting down. Message will not be processed and will be retried after {message.LockedUntilUtc}.");
                return;
            }

            try
            {
                IncomingMessageDetails incomingMessage;
                try
                {
                    incomingMessage = brokeredMessageConverter.Convert(message);
                }
                catch (UnsupportedBrokeredMessageBodyTypeException exception)
                {
                    await message.DeadLetterAsync("BrokeredMessage to IncomingMessageDetails conversion failure", exception.ToString()).ConfigureAwait(false);

                    return;
                }

                var context = new BrokeredMessageReceiveContext(message, entity, internalReceiver.Mode);
                try
                {
                    var scope = wrapInScope ? new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions
                    {
                        IsolationLevel = IsolationLevel.Serializable
                    }, TransactionScopeAsyncFlowOption.Enabled) : null;
                    {
                        using (scope)
                        {
                            await incomingCallback(incomingMessage, context).ConfigureAwait(false);

                            if (context.CancellationToken.IsCancellationRequested)
                            {
                                await AbandonOnCancellation(message).ConfigureAwait(false);
                            }
                            else
                            {
                                var wasCompleted = await HandleCompletion(message, context, completionCanBeBatched, slotNumber).ConfigureAwait(false);

                                if (wasCompleted)
                                {
                                    scope?.Complete();
                                }
                            }
                        }
                    }
                }
                catch (Exception exception) when(!stopping)
                {
                    // and go into recovery mode so that no new messages are added to the transfer queue
                    context.Recovering = true;

                    // pass the context into the error pipeline
                    var transportTransaction = new TransportTransaction();

                    transportTransaction.Set(context);
                    var errorContext = new ErrorContext(exception, incomingMessage.Headers, incomingMessage.MessageId, incomingMessage.Body, transportTransaction, message.DeliveryCount);

                    var result = await processingFailureCallback(errorContext).ConfigureAwait(false);

                    if (result == ErrorHandleResult.RetryRequired)
                    {
                        await Abandon(message, exception).ConfigureAwait(false);
                    }
                    else
                    {
                        await HandleCompletion(message, context, completionCanBeBatched, slotNumber).ConfigureAwait(false);
                    }
                }
            }
            catch (Exception onErrorException)
            {
                await Abandon(message, onErrorException).ConfigureAwait(false);
                await errorCallback(onErrorException).ConfigureAwait(false);
            }
        }