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); } } } }
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(); } }