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); } } }
/// <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; try { ServiceBusEventSource.Log.ProcessorMessageHandlerStart(_identifier, message.SequenceNumber); await OnMessageHandler(message, cancellationToken).ConfigureAwait(false); ServiceBusEventSource.Log.ProcessorMessageHandlerComplete(_identifier, message.SequenceNumber); } catch (Exception ex) { ServiceBusEventSource.Log.ProcessorMessageHandlerException(_identifier, message.SequenceNumber, ex.ToString()); throw; } if (Receiver.ReceiveMode == ReceiveMode.PeekLock && _processorOptions.AutoComplete && !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.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 ServiceBusFailureReason?failureReason = (ex as ServiceBusException)?.Reason; if (!message.IsSettled && _receiverOptions.ReceiveMode == ReceiveMode.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( 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(); } }