async Task _handle(IncomingStepContext context, Func <Task> next, string identifierToTrackMessageBy, ITransactionContext transactionContext, string messageId, string secondLevelMessageId = null) { try { await next(); await transactionContext.Commit(); _errorTracker.CleanUp(messageId); if (secondLevelMessageId != null) { _errorTracker.CleanUp(secondLevelMessageId); } } catch (OperationCanceledException) when(_cancellationToken.IsCancellationRequested) { _logger.Info("Dispatch of message with ID {messageId} was cancelled", messageId); transactionContext.Abort(); } catch (Exception exception) { _errorTracker.RegisterError(identifierToTrackMessageBy, exception); _checkFinal(context); await _handleError(context, next, identifierToTrackMessageBy); } }
/// <summary> /// Executes the entire message processing pipeline in an exception handler, tracking the number of failed delivery attempts. /// Forwards the message to the error queue when the max number of delivery attempts has been exceeded. /// </summary> public async Task Process(IncomingStepContext context, Func <Task> next) { var transportMessage = context.Load <TransportMessage>(); var transactionContext = context.Load <ITransactionContext>(); var messageId = transportMessage.Headers.GetValueOrNull(Headers.MessageId); if (string.IsNullOrWhiteSpace(messageId)) { await MoveMessageToErrorQueue("<no message ID>", transportMessage, transactionContext, string.Format("Received message with empty or absent '{0}' header! All messages must be" + " supplied with an ID . If no ID is present, the message cannot be tracked" + " between delivery attempts, and other stuff would also be much harder to" + " do - therefore, it is a requirement that messages be supplied with an ID.", Headers.MessageId), shortErrorDescription : string.Format("Received message with empty or absent '{0}' header", Headers.MessageId)); return; } if (_errorTracker.HasFailedTooManyTimes(messageId)) { // if we don't have 2nd level retries, just get the message out of the way if (!_simpleRetryStrategySettings.SecondLevelRetriesEnabled) { await MoveMessageToErrorQueue(messageId, transportMessage, transactionContext, GetErrorDescriptionFor(messageId), GetErrorDescriptionFor(messageId, brief : true)); _errorTracker.CleanUp(messageId); return; } // change the identifier to track by to perform this 2nd level of delivery attempts var secondLevelMessageId = messageId + "-2nd-level"; if (_errorTracker.HasFailedTooManyTimes(secondLevelMessageId)) { await MoveMessageToErrorQueue(messageId, transportMessage, transactionContext, GetErrorDescriptionFor(messageId), GetErrorDescriptionFor(messageId, brief : true)); _errorTracker.CleanUp(messageId); _errorTracker.CleanUp(secondLevelMessageId); return; } context.Save(DispatchAsFailedMessageKey, true); await DispatchWithTrackerIdentifier(next, secondLevelMessageId, transactionContext); return; } await DispatchWithTrackerIdentifier(next, messageId, transactionContext); }
/// <summary> /// Executes the entire message processing pipeline in an exception handler, tracking the number of failed delivery attempts. /// Forwards the message to the error queue when the max number of delivery attempts has been exceeded. /// </summary> public async Task Process(IncomingStepContext context, Func <Task> next) { var transportMessage = context.Load <TransportMessage>() ?? throw new RebusApplicationException("Could not find a transport message in the current incoming step context"); var transactionContext = context.Load <ITransactionContext>() ?? throw new RebusApplicationException("Could not find a transaction context in the current incoming step context"); var messageId = transportMessage.Headers.GetValueOrNull(Headers.MessageId); if (string.IsNullOrWhiteSpace(messageId)) { await MoveMessageToErrorQueue(context, transactionContext, new RebusApplicationException($"Received message with empty or absent '{Headers.MessageId}' header! All messages must be" + " supplied with an ID . If no ID is present, the message cannot be tracked" + " between delivery attempts, and other stuff would also be much harder to" + " do - therefore, it is a requirement that messages be supplied with an ID.")); return; } if (_errorTracker.HasFailedTooManyTimes(messageId)) { // if we don't have 2nd level retries, just get the message out of the way if (!_simpleRetryStrategySettings.SecondLevelRetriesEnabled) { var aggregateException = GetAggregateException(messageId); await MoveMessageToErrorQueue(context, transactionContext, aggregateException); _errorTracker.CleanUp(messageId); return; } // change the identifier to track by to perform this 2nd level of delivery attempts var secondLevelMessageId = GetSecondLevelMessageId(messageId); if (_errorTracker.HasFailedTooManyTimes(secondLevelMessageId)) { var aggregateException = GetAggregateException(messageId, secondLevelMessageId); await MoveMessageToErrorQueue(context, transactionContext, aggregateException); _errorTracker.CleanUp(messageId); _errorTracker.CleanUp(secondLevelMessageId); return; } context.Save(DispatchAsFailedMessageKey, true); await DispatchWithTrackerIdentifier(next, secondLevelMessageId, transactionContext, messageId, secondLevelMessageId); return; } await DispatchWithTrackerIdentifier(next, messageId, transactionContext, messageId); }
public void CleanUp(string messageId) { _innerErrorTracker.CleanUp(messageId); }