async Task MessageDispatchTask(Message message)
        {
            CancellationTokenSource renewLockCancellationTokenSource = null;
            Timer autoRenewLockCancellationTimer = null;

            MessagingEventSource.Log.MessageReceiverPumpDispatchTaskStart(this.messageReceiver.ClientId, message);

            if (this.ShouldRenewLock())
            {
                renewLockCancellationTokenSource = new CancellationTokenSource();
                TaskExtensionHelper.Schedule(() => this.RenewMessageLockTask(message, renewLockCancellationTokenSource.Token));

                // After a threshold time of renewal('AutoRenewTimeout'), create timer to cancel anymore renewals.
                autoRenewLockCancellationTimer = new Timer(this.CancelAutoRenewLock, renewLockCancellationTokenSource, this.registerHandlerOptions.MaxAutoRenewDuration, TimeSpan.FromMilliseconds(-1));
            }

            try
            {
                MessagingEventSource.Log.MessageReceiverPumpUserCallbackStart(this.messageReceiver.ClientId, message);
                await this.onMessageCallback(message, this.pumpCancellationToken).ConfigureAwait(false);

                MessagingEventSource.Log.MessageReceiverPumpUserCallbackStop(this.messageReceiver.ClientId, message);
            }
            catch (Exception exception)
            {
                MessagingEventSource.Log.MessageReceiverPumpUserCallbackException(this.messageReceiver.ClientId, message, exception);
                await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.UserCallback).ConfigureAwait(false);

                // Nothing much to do if UserCallback throws, Abandon message and Release semaphore.
                if (!(exception is MessageLockLostException))
                {
                    await this.AbandonMessageIfNeededAsync(message).ConfigureAwait(false);
                }

                if (ServiceBusDiagnosticSource.IsEnabled())
                {
                    this.diagnosticSource.ReportException(exception);
                }
                // AbandonMessageIfNeededAsync should take care of not throwing exception
                this.maxConcurrentCallsSemaphoreSlim.Release();

                return;
            }
            finally
            {
                renewLockCancellationTokenSource?.Cancel();
                renewLockCancellationTokenSource?.Dispose();
                autoRenewLockCancellationTimer?.Dispose();
            }

            // If we've made it this far, user callback completed fine. Complete message and Release semaphore.
            await this.CompleteMessageIfNeededAsync(message).ConfigureAwait(false);

            this.maxConcurrentCallsSemaphoreSlim.Release();

            MessagingEventSource.Log.MessageReceiverPumpDispatchTaskStop(this.messageReceiver.ClientId, message, this.maxConcurrentCallsSemaphoreSlim.CurrentCount);
        }
        async Task MessagePumpTaskAsync()
        {
            while (!this.pumpCancellationToken.IsCancellationRequested)
            {
                Message message = null;
                try
                {
                    await this.maxConcurrentCallsSemaphoreSlim.WaitAsync(this.pumpCancellationToken).ConfigureAwait(false);

                    message = await this.messageReceiver.ReceiveAsync(this.registerHandlerOptions.ReceiveTimeOut).ConfigureAwait(false);

                    if (message != null)
                    {
                        MessagingEventSource.Log.MessageReceiverPumpTaskStart(this.messageReceiver.ClientId, message, this.maxConcurrentCallsSemaphoreSlim.CurrentCount);

                        TaskExtensionHelper.Schedule(() =>
                        {
                            if (ServiceBusDiagnosticSource.IsEnabled())
                            {
                                return(this.MessageDispatchTaskInstrumented(message));
                            }
                            else
                            {
                                return(this.MessageDispatchTask(message));
                            }
                        });
                    }
                }
                catch (Exception exception)
                {
                    // Not reporting an ObjectDisposedException as we're stopping the pump
                    if (!(exception is ObjectDisposedException && this.pumpCancellationToken.IsCancellationRequested))
                    {
                        MessagingEventSource.Log.MessageReceivePumpTaskException(this.messageReceiver.ClientId, string.Empty, exception);
                        await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.Receive).ConfigureAwait(false);
                    }
                }
                finally
                {
                    // Either an exception or for some reason message was null, release semaphore and retry.
                    if (message == null)
                    {
                        this.maxConcurrentCallsSemaphoreSlim.Release();
                        MessagingEventSource.Log.MessageReceiverPumpTaskStop(this.messageReceiver.ClientId, this.maxConcurrentCallsSemaphoreSlim.CurrentCount);
                    }
                }
            }
        }
예제 #3
0
        async Task MessagePumpTaskAsync(IMessageSession session)
        {
            if (session == null)
            {
                return;
            }

            var renewLockCancellationTokenSource = new CancellationTokenSource();

            if (this.ShouldRenewSessionLock())
            {
                TaskExtensionHelper.Schedule(() => this.RenewSessionLockTaskAsync(session, renewLockCancellationTokenSource.Token));
            }

            var autoRenewLockCancellationTimer = new Timer(
                CancelAutoRenewLock,
                renewLockCancellationTokenSource,
                Timeout.Infinite,
                Timeout.Infinite);

            try
            {
                while (!this.pumpCancellationToken.IsCancellationRequested && !session.IsClosedOrClosing)
                {
                    Message message;
                    try
                    {
                        message = await session.ReceiveAsync(this.sessionHandlerOptions.MessageWaitTimeout).ConfigureAwait(false);
                    }
                    catch (Exception exception)
                    {
                        MessagingEventSource.Log.MessageReceivePumpTaskException(this.clientId, session.SessionId, exception);
                        if (exception is ServiceBusTimeoutException)
                        {
                            // Timeout Exceptions are pretty common. Not alerting the User on this.
                            continue;
                        }

                        if (!(exception is ObjectDisposedException && this.pumpCancellationToken.IsCancellationRequested))
                        {
                            await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.Receive).ConfigureAwait(false);
                        }
                        break;
                    }

                    if (message == null)
                    {
                        MessagingEventSource.Log.SessionReceivePumpSessionEmpty(this.clientId, session.SessionId);
                        break;
                    }

                    bool     isDiagnosticSourceEnabled = ServiceBusDiagnosticSource.IsEnabled();
                    Activity activity    = isDiagnosticSourceEnabled ? this.diagnosticSource.ProcessSessionStart(session, message) : null;
                    Task     processTask = null;

                    try
                    {
                        // Set the timer
                        autoRenewLockCancellationTimer.Change(this.sessionHandlerOptions.MaxAutoRenewDuration,
                                                              TimeSpan.FromMilliseconds(-1));
                        var callbackExceptionOccurred = false;
                        try
                        {
                            processTask = this.userOnSessionCallback(session, message, this.pumpCancellationToken);
                            await processTask.ConfigureAwait(false);
                        }
                        catch (Exception exception)
                        {
                            if (isDiagnosticSourceEnabled)
                            {
                                this.diagnosticSource.ReportException(exception);
                            }

                            MessagingEventSource.Log.MessageReceivePumpTaskException(this.clientId, session.SessionId, exception);
                            await this.RaiseExceptionReceived(exception, ExceptionReceivedEventArgsAction.UserCallback).ConfigureAwait(false);

                            callbackExceptionOccurred = true;
                            if (!(exception is MessageLockLostException || exception is SessionLockLostException))
                            {
                                await this.AbandonMessageIfNeededAsync(session, message).ConfigureAwait(false);
                            }
                        }
                        finally
                        {
                            autoRenewLockCancellationTimer.Change(Timeout.Infinite, Timeout.Infinite);
                        }

                        if (!callbackExceptionOccurred)
                        {
                            await this.CompleteMessageIfNeededAsync(session, message).ConfigureAwait(false);
                        }
                        else if (session.IsClosedOrClosing)
                        {
                            // If User closed the session as part of the callback, break out of the loop
                            break;
                        }
                    }
                    finally
                    {
                        this.diagnosticSource.ProcessSessionStop(activity, session, message, processTask?.Status);
                    }
                }
            }
            finally
            {
                renewLockCancellationTokenSource.Cancel();
                renewLockCancellationTokenSource.Dispose();
                autoRenewLockCancellationTimer.Dispose();

                await this.CloseSessionIfNeededAsync(session).ConfigureAwait(false);

                this.maxConcurrentSessionsSemaphoreSlim.Release();
            }
        }