private async Task AbortCoreAsync(SequenceAbortReason reason, Exception?exception) { bool alreadyAborted; lock (_abortLockObject) { alreadyAborted = IsAborted; if (!alreadyAborted) { _abortingTaskCompletionSource = new TaskCompletionSource <bool>(); if (reason > AbortReason) { AbortReason = reason; AbortException = exception; } } } if (alreadyAborted) { // Multiple calls to AbortAsync should await until the sequence is aborted for real, // otherwise the TransactionHandlerConsumerBehavior could continue before the abort // is done, preventing the error policies to be correctly and successfully applied. await _abortingTaskCompletionSource !.Task.ConfigureAwait(false); return; } _logger.LogTrace( IntegrationEventIds.LowLevelTracing, AbortException, "Aborting {sequenceType} '{sequenceId}' ({abortReason})...", GetType().Name, SequenceId, AbortReason); _timeoutCancellationTokenSource?.Cancel(); await Context.SequenceStore.RemoveAsync(SequenceId).ConfigureAwait(false); if (await HandleExceptionAsync(exception).ConfigureAwait(false)) { _logger.LogSequenceAborted(Context.Envelope, this, AbortReason, AbortException); } _streamProvider.Abort(); _abortCancellationTokenSource.Cancel(); _abortingTaskCompletionSource?.SetResult(true); }
/// <inheritdoc cref="ISequence.AbortAsync" /> public Task AbortAsync(SequenceAbortReason reason, Exception?exception = null) { if (reason == SequenceAbortReason.None) { throw new ArgumentOutOfRangeException(nameof(reason), reason, "Reason not specified."); } if (reason == SequenceAbortReason.Error && exception == null) { throw new ArgumentNullException( nameof(exception), "The exception must be specified if the reason is Error."); } return(AbortCoreAsync(reason, exception)); }
public void LogSequenceAborted( ConsumerPipelineContext context, ISequence sequence, SequenceAbortReason reason, Exception?exception) { switch (reason) { case SequenceAbortReason.Error: LogWithMessageInfo( LogLevel.Warning, IntegrationEventIds.ErrorProcessingInboundMessage, exception, "Error occurred processing the inbound sequence of messages.", context.Envelope, sequence, context.Consumer.Id); break; case SequenceAbortReason.IncompleteSequence: LogWithMessageInfo( LogLevel.Warning, IntegrationEventIds.IncompleteSequenceDiscarded, null, "The incomplete sequence is discarded.", context.Envelope, sequence, context.Consumer.Id); break; case SequenceAbortReason.EnumerationAborted: case SequenceAbortReason.ConsumerAborted: case SequenceAbortReason.Disposing: LogWithMessageInfo( LogLevel.Debug, IntegrationEventIds.SequenceProcessingAborted, null, $"The sequence processing has been aborted (reason: {reason}).", context.Envelope, sequence, context.Consumer.Id); break; default: throw new ArgumentOutOfRangeException(nameof(reason), reason, null); } }
public static Task DisposeAllAsync( this IEnumerable <ISequenceStore> stores, SequenceAbortReason abortReason) => stores .SelectMany(store => store) .ToList() .ParallelForEachAsync( async sequence => { if (sequence.IsPending) { await sequence.AbortAsync(abortReason) .ConfigureAwait(false); } await sequence.AwaitProcessingAsync(false).ConfigureAwait(false); });
public static void LogSequenceAborted( this ISilverbackLogger logger, ISequence sequence, SequenceAbortReason reason) { if (!logger.IsEnabled(IntegrationLogEvents.SequenceProcessingAborted)) { return; } SequenceProcessingAborted( logger.InnerLogger, sequence.GetType().Name, sequence.SequenceId, sequence.Length, reason, null); }