/// <summary>
 /// Initializes a new instance of the <see cref="ProcessErrorEventArgs" /> class.
 /// </summary>
 ///
 /// <param name="exception">The exception that triggered the call to the error event handler.</param>
 /// <param name="errorSource">The source associated with the error.</param>
 /// <param name="fullyQualifiedNamespace">The endpoint used when this exception occurred.</param>
 /// <param name="entityPath">The entity path used when this exception occurred.</param>
 public ProcessErrorEventArgs(
     Exception exception,
     ServiceBusErrorSource errorSource,
     string fullyQualifiedNamespace,
     string entityPath)
 {
     Exception               = exception;
     ErrorSource             = errorSource;
     FullyQualifiedNamespace = fullyQualifiedNamespace;
     EntityPath              = entityPath;
 }
示例#2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ProcessErrorEventArgs" /> class.
 /// </summary>
 ///
 /// <param name="exception">The exception that triggered the call to the error event handler.</param>
 /// <param name="errorSource">The source associated with the error.</param>
 /// <param name="fullyQualifiedNamespace">The endpoint used when this exception occurred.</param>
 /// <param name="entityPath">The entity path used when this exception occurred.</param>
 /// <param name="cancellationToken">The processor's <see cref="System.Threading.CancellationToken"/> instance which will be cancelled
 /// in the event that <see cref="ServiceBusProcessor.StopProcessingAsync"/> is called.</param>
 public ProcessErrorEventArgs(
     Exception exception,
     ServiceBusErrorSource errorSource,
     string fullyQualifiedNamespace,
     string entityPath,
     CancellationToken cancellationToken)
 {
     Exception               = exception;
     ErrorSource             = errorSource;
     FullyQualifiedNamespace = fullyQualifiedNamespace;
     EntityPath              = entityPath;
     CancellationToken       = cancellationToken;
 }
示例#3
0
        private static void ThrowIfSessionLockLost(
            Exception exception,
            ServiceBusErrorSource errorSource)
        {
            // we need to propagate this in order to dispose the session receiver
            // in the same place where we are creating them.
            var sbException = exception as ServiceBusException;

            if (sbException?.Reason == ServiceBusException.FailureReason.SessionLockLost)
            {
                sbException.ProcessorErrorSource = errorSource;
                throw sbException;
            }
        }
示例#4
0
        public virtual async Task ReceiveAndProcessMessagesAsync(CancellationToken cancellationToken)
        {
            ServiceBusErrorSource errorSource = ServiceBusErrorSource.Receive;

            try
            {
                // loop within the context of this thread
                while (!cancellationToken.IsCancellationRequested && !Processor.Connection.IsClosed)
                {
                    errorSource = ServiceBusErrorSource.Receive;
                    IReadOnlyList <ServiceBusReceivedMessage> messages = await Receiver.ReceiveMessagesAsync(
                        maxMessages : 1,
                        maxWaitTime : _maxReceiveWaitTime,
                        isProcessor : true,
                        cancellationToken : cancellationToken).ConfigureAwait(false);

                    ServiceBusReceivedMessage message = messages.Count == 0 ? null : messages[0];
                    if (message == null)
                    {
                        continue;
                    }
                    await ProcessOneMessageWithinScopeAsync(
                        message,
                        DiagnosticProperty.ProcessMessageActivityName,
                        cancellationToken).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
                // If the user manually throws a TCE, then we should log it.
                when(!(ex is TaskCanceledException) ||
                     !cancellationToken.IsCancellationRequested)
                {
                    if (ex is ServiceBusException sbException && sbException.ProcessorErrorSource.HasValue)
                    {
                        errorSource = sbException.ProcessorErrorSource.Value;
                    }
                    await RaiseExceptionReceived(
                        new ProcessErrorEventArgs(
                            ex,
                            errorSource,
                            Processor.FullyQualifiedNamespace,
                            Processor.EntityPath,
                            cancellationToken))
                    .ConfigureAwait(false);
                }
        }
示例#5
0
        public virtual async Task ReceiveAndProcessMessagesAsync(CancellationToken cancellationToken)
        {
            ServiceBusErrorSource errorSource = ServiceBusErrorSource.Receive;

            try
            {
                // loop within the context of this thread
                while (!cancellationToken.IsCancellationRequested)
                {
                    errorSource = ServiceBusErrorSource.Receive;
                    ServiceBusReceivedMessage message = await Receiver.ReceiveAsync(
                        _maxReceiveWaitTime,
                        cancellationToken).ConfigureAwait(false);

                    if (message == null)
                    {
                        continue;
                    }

                    await ProcessOneMessage(
                        message,
                        cancellationToken)
                    .ConfigureAwait(false);
                }
            }
            catch (Exception ex) when(!(ex is TaskCanceledException))
            {
                if (ex is ServiceBusException sbException && sbException.ProcessorErrorSource.HasValue)
                {
                    errorSource = sbException.ProcessorErrorSource.Value;
                }
                await RaiseExceptionReceived(
                    new ProcessErrorEventArgs(
                        ex,
                        errorSource,
                        _fullyQualifiedNamespace,
                        _entityPath))
                .ConfigureAwait(false);
            }
        }
        public override async Task ReceiveAndProcessMessagesAsync(
            CancellationToken cancellationToken)
        {
            ServiceBusErrorSource errorSource = ServiceBusErrorSource.Receive;

            try
            {
                errorSource = ServiceBusErrorSource.AcceptMessageSession;
                bool releaseSemaphore = false;
                try
                {
                    try
                    {
                        await _concurrentAcceptSessionsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);

                        // only attempt to release semaphore if WaitAsync is successful,
                        // otherwise SemaphoreFullException can occur.
                        releaseSemaphore = true;
                    }
                    catch (OperationCanceledException)
                    {
                        // propagate as TCE so it will be handled by the outer catch block
                        throw new TaskCanceledException();
                    }
                    try
                    {
                        await EnsureReceiverCreated(cancellationToken).ConfigureAwait(false);
                    }
                    catch (ServiceBusException ex)
                        when(ex.Reason == ServiceBusException.FailureReason.ServiceTimeout)
                        {
                            // these exceptions are expected when no messages are available
                            // so simply return and allow this to be tried again on next thread
                            return;
                        }
                }
                finally
                {
                    if (releaseSemaphore)
                    {
                        _concurrentAcceptSessionsSemaphore.Release();
                    }
                }

                // loop within the context of this thread
                while (!cancellationToken.IsCancellationRequested)
                {
                    errorSource = ServiceBusErrorSource.Receive;
                    ServiceBusReceivedMessage message = await _receiver.ReceiveMessageAsync(
                        _maxReceiveWaitTime,
                        cancellationToken).ConfigureAwait(false);

                    if (message == null)
                    {
                        // Break out of the loop to allow a new session to
                        // be processed.
                        break;
                    }
                    await ProcessOneMessageWithinScopeAsync(
                        message,
                        DiagnosticProperty.ProcessSessionMessageActivityName,
                        cancellationToken).ConfigureAwait(false);
                }
            }
            catch (Exception ex) when(!(ex is TaskCanceledException))
            {
                if (ex is ServiceBusException sbException && sbException.ProcessorErrorSource.HasValue)
                {
                    errorSource = sbException.ProcessorErrorSource.Value;
                }
                await RaiseExceptionReceived(
                    new ProcessErrorEventArgs(
                        ex,
                        errorSource,
                        _fullyQualifiedNamespace,
                        _entityPath))
                .ConfigureAwait(false);
            }
            finally
            {
                await CloseReceiverIfNeeded(cancellationToken).ConfigureAwait(false);
            }
        }
        public override async Task ReceiveAndProcessMessagesAsync(CancellationToken processorCancellationToken)
        {
            ServiceBusErrorSource errorSource = ServiceBusErrorSource.AcceptMessageSession;
            bool canProcess = false;

            try
            {
                try
                {
                    canProcess = await EnsureCanProcess(processorCancellationToken).ConfigureAwait(false);

                    if (!canProcess)
                    {
                        return;
                    }
                }
                catch (ServiceBusException ex)
                    when(ex.Reason == ServiceBusFailureReason.ServiceTimeout)
                    {
                        // these exceptions are expected when no messages are available
                        // so simply return and allow this to be tried again on next thread
                        return;
                    }
                // loop within the context of this thread
                while (!_sessionCancellationSource.Token.IsCancellationRequested)
                {
                    errorSource = ServiceBusErrorSource.Receive;
                    ServiceBusReceivedMessage message = await _receiver.ReceiveMessageAsync(
                        _maxReceiveWaitTime,
                        _sessionCancellationSource.Token).ConfigureAwait(false);

                    if (message == null)
                    {
                        // Break out of the loop to allow a new session to
                        // be processed.
                        break;
                    }
                    await ProcessOneMessageWithinScopeAsync(
                        message,
                        DiagnosticProperty.ProcessSessionMessageActivityName,
                        _sessionCancellationSource.Token).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
                when(!(ex is TaskCanceledException) ||
                     // If the user manually throws a TCE, then we should log it.
                     (!_sessionCancellationSource.IsCancellationRequested &&
                      // Even though the _sessionCancellationSource is linked to processorCancellationToken,
                      // we need to check both here in case the processor token gets cancelled before the
                      // session token is linked.
                      !processorCancellationToken.IsCancellationRequested))
                {
                    if (ex is ServiceBusException sbException && sbException.ProcessorErrorSource.HasValue)
                    {
                        errorSource = sbException.ProcessorErrorSource.Value;

                        // Signal cancellation so user event handlers can stop whatever processing they are doing
                        // as soon as we know the session lock has been lost. Note, we don't have analogous handling
                        // for message locks in ReceiverManager, because there is only ever one thread processing a
                        // single message at one time, so cancelling the token there would serve no purpose.
                        if (sbException.Reason == ServiceBusFailureReason.SessionLockLost)
                        {
                            _sessionCancellationSource.Cancel();
                        }
                    }
                    await RaiseExceptionReceived(
                        new ProcessErrorEventArgs(
                            ex,
                            errorSource,
                            _fullyQualifiedNamespace,
                            _entityPath))
                    .ConfigureAwait(false);
                }
            finally
            {
                if (canProcess)
                {
                    await CloseReceiverIfNeeded(
                        processorCancellationToken).ConfigureAwait(false);
                }
            }
        }
示例#8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="message"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task ProcessOneMessage(
            ServiceBusReceivedMessage message,
            CancellationToken cancellationToken)
        {
            ServiceBusErrorSource   errorSource = ServiceBusErrorSource.Receive;
            CancellationTokenSource renewLockCancellationTokenSource = null;
            Task renewLock = null;

            try
            {
                if (!Receiver.IsSessionReceiver &&
                    Receiver.ReceiveMode == ReceiveMode.PeekLock &&
                    AutoRenewLock)
                {
                    renewLockCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                    renewLock = RenewMessageLock(
                        message,
                        renewLockCancellationTokenSource);
                }

                errorSource = ServiceBusErrorSource.UserCallback;

                await OnMessageHandler(message, cancellationToken).ConfigureAwait(false);

                if (Receiver.ReceiveMode == ReceiveMode.PeekLock &&
                    _processorOptions.AutoComplete &&
                    !message.IsSettled)
                {
                    errorSource = ServiceBusErrorSource.Complete;
                    // don't pass the processor cancellation token
                    // as we want in flight autocompletion to be able
                    // to finish
                    await Receiver.CompleteMessageAsync(
                        message.LockToken,
                        CancellationToken.None)
                    .ConfigureAwait(false);
                }

                await CancelTask(renewLockCancellationTokenSource, renewLock).ConfigureAwait(false);
            }
            catch (Exception ex)
                // This prevents exceptions relating to processing a message from bubbling up all
                // the way to the main thread when calling StopProcessingAsync, which we don't want
                // as it isn't actionable.
                when(!(ex is TaskCanceledException) || !cancellationToken.IsCancellationRequested)
                {
                    ThrowIfSessionLockLost(ex, errorSource);
                    await RaiseExceptionReceived(
                        new ProcessErrorEventArgs(
                            ex,
                            errorSource,
                            _fullyQualifiedNamespace,
                            _entityPath))
                    .ConfigureAwait(false);

                    // if the user settled the message, or if the message or session lock was lost,
                    // do not attempt to abandon the message
                    ServiceBusException.FailureReason?failureReason = (ex as ServiceBusException)?.Reason;
                    if (!message.IsSettled &&
                        _receiverOptions.ReceiveMode == ReceiveMode.PeekLock &&
                        failureReason != ServiceBusException.FailureReason.SessionLockLost &&
                        failureReason != ServiceBusException.FailureReason.MessageLockLost)
                    {
                        try
                        {
                            // don't pass the processor cancellation token
                            // as we want in flight abandon to be able
                            // to finish even if user stopped processing
                            await Receiver.AbandonMessageAsync(
                                message.LockToken,
                                cancellationToken : CancellationToken.None)
                            .ConfigureAwait(false);
                        }
                        catch (Exception exception)
                        {
                            ThrowIfSessionLockLost(exception, ServiceBusErrorSource.Abandon);
                            await RaiseExceptionReceived(
                                new ProcessErrorEventArgs(
                                    exception,
                                    ServiceBusErrorSource.Abandon,
                                    _fullyQualifiedNamespace,
                                    _entityPath))
                            .ConfigureAwait(false);
                        }
                    }
                }
            finally
            {
                renewLockCancellationTokenSource?.Cancel();
                renewLockCancellationTokenSource?.Dispose();
            }
        }
示例#9
0
        private async Task ProcessOneMessage(
            ServiceBusReceivedMessage triggerMessage,
            CancellationToken cancellationToken)
        {
            ServiceBusErrorSource errorSource = ServiceBusErrorSource.Receive;
            EventArgs             args        = null;

            try
            {
                errorSource = ServiceBusErrorSource.ProcessMessageCallback;
                try
                {
                    ServiceBusEventSource.Log.ProcessorMessageHandlerStart(Processor.Identifier, triggerMessage.SequenceNumber,
                                                                           triggerMessage.LockTokenGuid);
                    args = await OnMessageHandler(triggerMessage, cancellationToken).ConfigureAwait(false);

                    ServiceBusEventSource.Log.ProcessorMessageHandlerComplete(Processor.Identifier, triggerMessage.SequenceNumber,
                                                                              triggerMessage.LockTokenGuid);
                }
                catch (Exception ex)
                {
                    ServiceBusEventSource.Log.ProcessorMessageHandlerException(Processor.Identifier, triggerMessage.SequenceNumber,
                                                                               ex.ToString(), triggerMessage.LockTokenGuid);
                    throw;
                }

                if (Receiver.ReceiveMode == ServiceBusReceiveMode.PeekLock && ProcessorOptions.AutoCompleteMessages)
                {
                    var messages = (args is ProcessMessageEventArgs processMessageEventArgs)
                        ? processMessageEventArgs.Messages.Keys
                        : ((ProcessSessionMessageEventArgs)args).Messages.Keys;
                    foreach (ServiceBusReceivedMessage message in messages)
                    {
                        if (!message.IsSettled)
                        {
                            errorSource = ServiceBusErrorSource.Complete;
                            // don't pass the processor cancellation token
                            // as we want in flight auto-completion to be able
                            // to finish
                            await Receiver.CompleteMessageAsync(
                                message,
                                CancellationToken.None)
                            .ConfigureAwait(false);

                            message.IsSettled = true;
                        }
                    }
                }
            }
            catch (Exception ex)
                // This prevents exceptions relating to processing a message from bubbling up all
                // the way to the main thread when calling StopProcessingAsync, which we don't want
                // as it isn't actionable.
                when(!(ex is TaskCanceledException) || !cancellationToken.IsCancellationRequested)
                {
                    ThrowIfSessionLockLost(ex, errorSource);
                    await RaiseExceptionReceived(
                        new ProcessErrorEventArgs(
                            ex,
                            errorSource,
                            Processor.FullyQualifiedNamespace,
                            Processor.EntityPath,
                            cancellationToken))
                    .ConfigureAwait(false);

                    // if the user settled the message, or if the message or session lock was lost,
                    // do not attempt to abandon the message
                    ServiceBusFailureReason?failureReason = (ex as ServiceBusException)?.Reason;

                    if (!triggerMessage.IsSettled &&
                        _receiverOptions.ReceiveMode == ServiceBusReceiveMode.PeekLock &&
                        failureReason != ServiceBusFailureReason.SessionLockLost &&
                        failureReason != ServiceBusFailureReason.MessageLockLost)
                    {
                        try
                        {
                            // don't pass the processor cancellation token
                            // as we want in flight abandon to be able
                            // to finish even if user stopped processing
                            await Receiver.AbandonMessageAsync(
                                triggerMessage.LockTokenGuid,
                                cancellationToken : CancellationToken.None)
                            .ConfigureAwait(false);
                        }
                        catch (Exception exception)
                        {
                            ThrowIfSessionLockLost(exception, ServiceBusErrorSource.Abandon);
                            await RaiseExceptionReceived(
                                new ProcessErrorEventArgs(
                                    exception,
                                    ServiceBusErrorSource.Abandon,
                                    Processor.FullyQualifiedNamespace,
                                    Processor.EntityPath,
                                    cancellationToken))
                            .ConfigureAwait(false);
                        }
                    }
                }
            finally
            {
                if (args is ProcessMessageEventArgs processMessageEventArgs)
                {
                    await processMessageEventArgs.CancelMessageLockRenewalAsync().ConfigureAwait(false);
                }
            }
        }
示例#10
0
        public override async Task ReceiveAndProcessMessagesAsync(CancellationToken processorCancellationToken)
        {
            ServiceBusErrorSource errorSource = ServiceBusErrorSource.AcceptSession;
            bool canProcess = false;

            try
            {
                try
                {
                    canProcess = await EnsureCanProcess(processorCancellationToken).ConfigureAwait(false);

                    if (!canProcess)
                    {
                        return;
                    }
                }
                catch (ServiceBusException ex)
                    when(ex.Reason == ServiceBusFailureReason.ServiceTimeout)
                    {
                        // these exceptions are expected when no messages are available
                        // so simply return and allow this to be tried again on next thread
                        return;
                    }

                using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(processorCancellationToken, _sessionCancellationSource.Token);
                // loop within the context of this thread
                while (!linkedTokenSource.Token.IsCancellationRequested)
                {
                    errorSource = ServiceBusErrorSource.Receive;
                    IReadOnlyList <ServiceBusReceivedMessage> messages = await Receiver.ReceiveMessagesAsync(
                        maxMessages : 1,
                        maxWaitTime : _maxReceiveWaitTime,
                        isProcessor : true,
                        cancellationToken : linkedTokenSource.Token).ConfigureAwait(false);

                    ServiceBusReceivedMessage message = messages.Count == 0 ? null : messages[0];
                    if (message == null)
                    {
                        // Break out of the loop to allow a new session to
                        // be processed.
                        _receiveTimeout = true;
                        break;
                    }
                    await ProcessOneMessageWithinScopeAsync(
                        message,
                        DiagnosticProperty.ProcessSessionMessageActivityName,
                        linkedTokenSource.Token).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
                when(ex is not TaskCanceledException)
                {
                    if (ex is ServiceBusException sbException)
                    {
                        if (sbException.ProcessorErrorSource.HasValue)
                        {
                            errorSource = sbException.ProcessorErrorSource.Value;
                        }

                        // Signal cancellation so user event handlers can stop whatever processing they are doing
                        // as soon as we know the session lock has been lost. Note, we don't have analogous handling
                        // for message locks in ReceiverManager, because there is only ever one thread processing a
                        // single message at one time, so cancelling the token there would serve no purpose.
                        if (sbException.Reason == ServiceBusFailureReason.SessionLockLost)
                        {
                            CancelSession();
                        }
                    }
                    await RaiseExceptionReceived(
                        new ProcessErrorEventArgs(
                            ex,
                            errorSource,
                            Processor.FullyQualifiedNamespace,
                            Processor.EntityPath,
                            processorCancellationToken))
                    .ConfigureAwait(false);
                }
            finally
            {
                if (canProcess)
                {
                    await CloseReceiverIfNeeded(processorCancellationToken).ConfigureAwait(false);
                }
            }
        }
示例#11
0
        public override async Task ReceiveAndProcessMessagesAsync(CancellationToken cancellationToken)
        {
            ServiceBusErrorSource errorSource = ServiceBusErrorSource.AcceptMessageSession;
            bool canProcess = false;

            try
            {
                try
                {
                    canProcess = await EnsureCanProcess(cancellationToken).ConfigureAwait(false);

                    if (!canProcess)
                    {
                        return;
                    }
                }
                catch (ServiceBusException ex)
                    when(ex.Reason == ServiceBusException.FailureReason.ServiceTimeout)
                    {
                        // these exceptions are expected when no messages are available
                        // so simply return and allow this to be tried again on next thread
                        return;
                    }

                // loop within the context of this thread
                while (!cancellationToken.IsCancellationRequested)
                {
                    errorSource = ServiceBusErrorSource.Receive;
                    ServiceBusReceivedMessage message = await _receiver.ReceiveMessageAsync(
                        _maxReceiveWaitTime,
                        cancellationToken).ConfigureAwait(false);

                    if (message == null)
                    {
                        // Break out of the loop to allow a new session to
                        // be processed.
                        break;
                    }
                    await ProcessOneMessageWithinScopeAsync(
                        message,
                        DiagnosticProperty.ProcessSessionMessageActivityName,
                        cancellationToken).ConfigureAwait(false);
                }
            }
            catch (Exception ex) when(!(ex is TaskCanceledException))
            {
                if (ex is ServiceBusException sbException && sbException.ProcessorErrorSource.HasValue)
                {
                    errorSource = sbException.ProcessorErrorSource.Value;
                }
                await RaiseExceptionReceived(
                    new ProcessErrorEventArgs(
                        ex,
                        errorSource,
                        _fullyQualifiedNamespace,
                        _entityPath))
                .ConfigureAwait(false);
            }
            finally
            {
                if (canProcess)
                {
                    await CloseReceiverIfNeeded(cancellationToken).ConfigureAwait(false);
                }
            }
        }