/// <summary> /// Called by the message processing loop to process an individual message /// </summary> /// <param name="queuedMessage">The queued message to process</param> /// <param name="cancellationToken">A cancellation token that can be used by the caller /// to cancel message processing operation</param> /// <returns>Returns a task that completes when the queued message is processed</returns> protected virtual async Task ProcessQueuedMessage(QueuedMessage queuedMessage, CancellationToken cancellationToken) { try { queuedMessage = queuedMessage.NextAttempt(); var acknowledged = await HandleMessageReceived(queuedMessage, cancellationToken); if (acknowledged) { await HandleMessageAcknowledged(queuedMessage, cancellationToken); return; } await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MessageNotAcknowledged) { Message = queuedMessage.Message, Queue = QueueName }.Build(), cancellationToken); if (queuedMessage.Attempts >= _maxAttempts) { await HandleMaximumAttemptsExceeded(queuedMessage, cancellationToken); return; } await HandleAcknowledgementFailure(queuedMessage); DiagnosticService.Emit( new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageRetry) { Detail = "Message not acknowledged; retrying in " + _retryDelay, Message = queuedMessage.Message, Queue = QueueName }.Build()); ScheduleRetry(queuedMessage, cancellationToken); } catch (Exception ex) { // Catch all. Do not let any exceptions propagate outside of this method! DiagnosticService.Emit( new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageProcessingError) { Detail = "Unhandled exception processing queued message", Message = queuedMessage.Message, Queue = QueueName, Exception = ex }.Build()); } }
private async Task <bool> HandleMessageReceived(QueuedMessage queuedMessage, CancellationToken cancellationToken) { Message message = null; var acknowledged = false; IPrincipal originalThreadPrincipal = null; try { originalThreadPrincipal = Thread.CurrentPrincipal; message = queuedMessage.Message; queuedMessage = queuedMessage.NextAttempt(); await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageAttempt) { Detail = "Processing queued message (attempt " + queuedMessage.Attempts + " of " + _maxAttempts + ")", Message = message, Queue = QueueName }.Build(), cancellationToken); var context = new QueuedMessageContext(message, queuedMessage.Principal); Thread.CurrentPrincipal = context.Principal; cancellationToken.ThrowIfCancellationRequested(); await _listener.MessageReceived(message, context, cancellationToken); if (_autoAcknowledge && !context.Acknowledged) { await context.Acknowledge(); } acknowledged = context.Acknowledged; } catch (Exception ex) { DiagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.UnhandledException) { Detail = "Unhandled exception handling queued message", Message = message, Queue = QueueName, Exception = ex }.Build()); } finally { Thread.CurrentPrincipal = originalThreadPrincipal; } return(acknowledged); }
/// <summary> /// Called by the message processing loop to process an individual message /// </summary> /// <param name="queuedMessage">The queued message to process</param> /// <param name="cancellationToken">A cancellation token that can be used by the caller /// to cancel message processing operation</param> /// <returns>Returns a task that completes when the queued message is processed</returns> protected virtual async Task ProcessQueuedMessage(QueuedMessage queuedMessage, CancellationToken cancellationToken) { Exception exception = null; var message = queuedMessage.Message; var principal = queuedMessage.Principal; // ReSharper disable once ConditionIsAlwaysTrueOrFalse queuedMessage = queuedMessage.NextAttempt(); await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageAttempt) { Detail = "Processing queued message (attempt " + queuedMessage.Attempts + " of " + _maxAttempts + ")", Message = message, Queue = QueueName }.Build(), cancellationToken); var context = new QueuedMessageContext(message, principal); Thread.CurrentPrincipal = context.Principal; cancellationToken.ThrowIfCancellationRequested(); try { await _listener.MessageReceived(message, context, cancellationToken); if (_autoAcknowledge && !context.Acknowledged) { await context.Acknowledge(); } } catch (Exception ex) { exception = ex; DiagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.UnhandledException) { Detail = "Unhandled exception handling queued message", Message = message, Queue = QueueName, Exception = ex }.Build()); } var eventArgs = new MessageQueueEventArgs(QueueName, queuedMessage, exception); if (context.Acknowledged) { await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MessageAcknowledged) { Message = message, Queue = QueueName }.Build(), cancellationToken); var messageAcknowledgedHandlers = MessageAcknowledged; if (messageAcknowledgedHandlers != null) { await messageAcknowledgedHandlers(this, eventArgs); } return; } await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MessageNotAcknowledged) { Message = message, Queue = QueueName }.Build(), cancellationToken); if (queuedMessage.Attempts >= _maxAttempts) { await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MaxAttemptsExceeded) { Detail = "Maximum attempts exceeded (" + _maxAttempts + ")", Message = message, Queue = QueueName }.Build(), cancellationToken); var maxAttemptsExceededHandlers = MaximumAttemptsExceeded; if (maxAttemptsExceededHandlers != null) { await MaximumAttemptsExceeded(this, eventArgs); } return; } var acknowledgementFailureHandlers = AcknowledgementFailure; if (acknowledgementFailureHandlers != null) { await AcknowledgementFailure(this, eventArgs); } await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageRetry) { Detail = "Message not acknowledged; retrying in " + _retryDelay, Message = message, Queue = QueueName }.Build(), cancellationToken); ScheduleRetry(queuedMessage, cancellationToken); }