public async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); try { // TODO: Ensure always disposed (TEST IT!) var scope = context.ServiceProvider.CreateScope(); context.ReplaceServiceScope(scope); context.TransactionManager = new ConsumerTransactionManager( context, context.ServiceProvider .GetRequiredService <ISilverbackIntegrationLogger <ConsumerTransactionManager> >()); await next(context).ConfigureAwait(false); if (context.Sequence == null) { await context.TransactionManager.CommitAsync().ConfigureAwait(false); context.Dispose(); } else { if (context.IsSequenceStart) { StartSequenceProcessingAwaiter(context); } await AwaitProcessedIfNecessaryAsync(context).ConfigureAwait(false); } } catch (Exception exception) { // Sequence errors are handled in AwaitSequenceProcessingAsync, just await the rollback and rethrow if (context.Sequence != null) { await context.Sequence.AbortAsync(SequenceAbortReason.Error, exception).ConfigureAwait(false); if (context.Sequence.Length > 0 && context.Sequence is ISequenceImplementation sequenceImpl) { _logger.LogTraceWithMessageInfo( IntegrationEventIds.LowLevelTracing, "Awaiting sequence processing completed before rethrowing.", context); await sequenceImpl.ProcessingCompletedTask.ConfigureAwait(false); } throw; } if (!await HandleExceptionAsync(context, exception).ConfigureAwait(false)) { throw; } } }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); if (context.Envelope.Endpoint.Encryption != null && context.Envelope.RawMessage != null) { string?keyIdentifier = null; if (context.Envelope.Endpoint.Encryption is SymmetricDecryptionSettings settings && settings.KeyProvider != null) { keyIdentifier = context.Envelope.Headers.GetValue(DefaultMessageHeaders.EncryptionKeyId); } context.Envelope.RawMessage = _streamFactory.GetDecryptStream( context.Envelope.RawMessage, context.Envelope.Endpoint.Encryption, keyIdentifier); } await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="SequencerConsumerBehaviorBase.PublishSequenceAsync" /> protected override Task PublishSequenceAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(next, nameof(next)); return(next(context)); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); _integrationSpy.AddRawInboundEnvelope(context.Envelope); return(next(context)); }
public Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { lock (_inboundEnvelopes) { _inboundEnvelopes.Add((IInboundEnvelope)context.Envelope); } return(next(context)); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); context.Envelope = await HandleAsync(context.Envelope).ConfigureAwait(false); await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); if (!await CheckIsAlreadyProcessedAsync(context).ConfigureAwait(false)) { await next(context).ConfigureAwait(false); } }
/// <inheritdoc cref="SequencerConsumerBehaviorBase.PublishSequenceAsync" /> protected override Task PublishSequenceAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); var processingTask = Task.Run(async() => await next(context).ConfigureAwait(false)); context.ProcessingTask ??= processingTask; return(Task.CompletedTask); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); if (_mappings != null && _mappings.Count > 0) { _mappings.Revert(context.Envelope.Headers); } await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); using var activity = ActivitySources.StartConsumeActivity(context.Envelope); _activityEnricherFactory.GetActivityEnricher(context.Envelope.Endpoint) .EnrichInboundActivity(activity, context); await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); if (context.Envelope is IInboundEnvelope inboundEnvelope) { HeaderAttributeHelper.SetFromHeaders( inboundEnvelope.Message, inboundEnvelope.Headers); } await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); if (context.Envelope.Endpoint.Encryption != null && !context.Envelope.Headers.Contains(DefaultMessageHeaders.Decrypted) && context.Envelope.RawMessage != null) { context.Envelope.RawMessage = _streamFactory.GetDecryptStream( context.Envelope.RawMessage, context.Envelope.Endpoint.Encryption); } await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); var newEnvelope = await DeserializeAsync(context).ConfigureAwait(false); if (newEnvelope == null) { _logger.LogNullMessageSkipped(context.Envelope); return; } context.Envelope = newEnvelope; await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); _logger.LogProcessing(context); if (context.Sequence != null) { if (context.Sequence is RawSequence) { await PublishEnvelopeAsync(context, context.Envelope.Endpoint.ThrowIfUnhandled) .ConfigureAwait(false); } else { await PublishSequenceAsync(context.Sequence, context).ConfigureAwait(false); } } else { var throwIfUnhandled = context.Envelope.Endpoint.ThrowIfUnhandled; if (context.Envelope is IInboundEnvelope envelope) { // TODO: Create only if necessary? var unboundedSequence = await GetUnboundedSequence(context).ConfigureAwait(false); int pushedStreamsCount = await unboundedSequence !.AddAsync(envelope, null, false).ConfigureAwait(false); if (unboundedSequence.IsAborted && unboundedSequence.AbortException != null) { throw unboundedSequence.AbortException; // TODO: Wrap into another exception? } throwIfUnhandled &= pushedStreamsCount == 0; } await PublishEnvelopeAsync(context, throwIfUnhandled).ConfigureAwait(false); } await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); try { await next(context).ConfigureAwait(false); } catch (Exception ex) { _logger.LogProcessingFatalError(context.Envelope, ex); throw new ConsumerPipelineFatalException( "Fatal error occurred processing the consumed message.", ex); } }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); if (context.Sequence != null) { if (context.Sequence is RawSequence) { await PublishEnvelopeAsync(context, context.Envelope.Endpoint.ThrowIfUnhandled) .ConfigureAwait(false); } else { await PublishSequenceAsync(context.Sequence, context).ConfigureAwait(false); } } else { var throwIfUnhandled = context.Envelope.Endpoint.ThrowIfUnhandled; if (HasAnyMessageStreamSubscriber(context) && context.Envelope is IInboundEnvelope envelope) { var unboundedSequence = await GetUnboundedSequenceAsync(context).ConfigureAwait(false); int pushedStreamsCount = await unboundedSequence !.AddAsync(envelope, null, false).ConfigureAwait(false); if (unboundedSequence.IsAborted && unboundedSequence.AbortException != null) { throw unboundedSequence.AbortException; } throwIfUnhandled &= pushedStreamsCount == 0; } await PublishEnvelopeAsync(context, throwIfUnhandled).ConfigureAwait(false); } await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="SequencerConsumerBehaviorBase.HandleAsync" /> public override async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { var rawSequence = Check.NotNull(context, nameof(context)).Sequence as ISequenceImplementation; try { await base.HandleAsync(context, next).ConfigureAwait(false); // Abort all pending sequences if the current message doesn't belong to a sequence if (context.Sequence == null) { await context.SequenceStore .GetPendingSequences() .ForEachAsync(sequence => sequence.AbortAsync(SequenceAbortReason.IncompleteSequence)) .ConfigureAwait(false); } } finally { rawSequence?.CompleteSequencerBehaviorsTask(); } }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); try { await next(context).ConfigureAwait(false); } catch (Exception ex) { _logger.LogCriticalWithMessageInfo( IntegrationEventIds.ConsumerFatalError, ex, "Fatal error occurred processing the consumed message. The consumer will be stopped.", context); throw; } }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); if (context.Envelope.Endpoint.MessageValidationMode != MessageValidationMode.None && context.Envelope is IInboundEnvelope deserializeEnvelope && deserializeEnvelope.Message != null) { (bool isValid, string?validationErrors) = MessageValidator.CheckMessageIsValid( deserializeEnvelope.Message, context.Envelope.Endpoint.MessageValidationMode); if (!isValid) { _logger.LogInvalidMessageProcessed(validationErrors !); } } await next(context).ConfigureAwait(false); }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public async Task HandleAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); var activity = new Activity(DiagnosticsConstants.ActivityNameMessageConsuming); try { TryInitActivity( context, activity, context.ServiceProvider.GetService <ISilverbackLogger <ActivityConsumerBehavior> >()); await next(context).ConfigureAwait(false); } finally { activity.Stop(); } }
private async Task <ISequence?> GetSequenceAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next, ISequenceReader sequenceReader) { var sequence = await sequenceReader.GetSequenceAsync(context).ConfigureAwait(false); if (sequence.IsComplete) { return(null); } if (sequence is IncompleteSequence incompleteSequence) { _logger.LogSkippingIncompleteSequence(incompleteSequence); return(null); } context.SetSequence(sequence, sequence.IsNew); if (sequence.IsNew) { StartActivityIfNeeded(sequence); await PublishSequenceAsync(context, next).ConfigureAwait(false); if (context.ProcessingTask != null) { MonitorProcessingTaskPrematureCompletion(context.ProcessingTask, sequence); } _logger.LogSequenceStarted(sequence); } return(sequence); }
public Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) => next(context);
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public virtual async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); var sequenceReader = await _sequenceReaders .FirstOrDefaultAsync(reader => reader.CanHandleAsync(context)) .ConfigureAwait(false); if (sequenceReader == null) { await next(context).ConfigureAwait(false); return; } // Store the original envelope in case it is replaced in the GetSequence method (see ChunkSequenceReader) var originalEnvelope = context.Envelope; // Store the previous sequence since it must be added to the new one (e.g. ChunkSequence into BatchSequence) var previousSequence = context.Sequence; ISequence?sequence; // Loop to handle edge cases where the sequence gets completed between the calls to // GetSequenceAsync and AddAsync while (true) { sequence = await GetSequenceAsync(context, next, sequenceReader).ConfigureAwait(false); if (sequence == null) { return; } if (!sequence.IsPending || sequence.IsCompleting) { continue; } await sequence.AddAsync(originalEnvelope, previousSequence).ConfigureAwait(false); AddSequenceTagToActivity(sequence); break; } _logger.LogMessageAddedToSequence(context.Envelope, sequence); if (sequence.IsComplete) { await AwaitOtherBehaviorIfNeededAsync(sequence).ConfigureAwait(false); // Mark the envelope as the end of the sequence only if the sequence wasn't swapped (e.g. chunk -> batch) if (sequence.Context.Sequence == null || sequence == sequence.Context.Sequence || sequence.Context.Sequence.IsCompleting || sequence.Context.Sequence.IsComplete) { context.SetIsSequenceEnd(); } _logger.LogSequenceCompleted(sequence); } }
/// <summary> /// Forwards the new sequence to the next behavior in the pipeline. /// </summary> /// <param name="context"> /// The context that is passed along the behaviors pipeline. /// </param> /// <param name="next"> /// The next behavior in the pipeline. /// </param> /// <returns> /// A <see cref="Task" /> representing the asynchronous operation. /// </returns> protected abstract Task PublishSequenceAsync( ConsumerPipelineContext context, ConsumerBehaviorHandler next);
public async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); try { var scope = context.ServiceProvider.CreateScope(); context.ReplaceServiceScope(scope); context.TransactionManager = new ConsumerTransactionManager( context, context.ServiceProvider .GetRequiredService <IInboundLogger <ConsumerTransactionManager> >()); _logger.LogProcessing(context.Envelope); await next(context).ConfigureAwait(false); if (context.Sequence == null) { await context.TransactionManager.CommitAsync().ConfigureAwait(false); context.Dispose(); } else { if (context.IsSequenceStart) { StartSequenceProcessingAwaiter(context); } await AwaitProcessedIfNecessaryAsync(context).ConfigureAwait(false); } } catch (Exception exception) { // Sequence errors are handled in AwaitSequenceProcessingAsync, just await the rollback and // rethrow (-> if the exception bubbled up till this point, it's because it failed to be // handled and it's safer to stop the consumer) if (context.Sequence != null) { await context.Sequence.AbortAsync(SequenceAbortReason.Error, exception) .ConfigureAwait(false); if (context.Sequence.Length > 0) { _logger.LogInboundLowLevelTrace( "Awaiting sequence processing completed before rethrowing.", context.Envelope); await context.Sequence.AwaitProcessingAsync(false).ConfigureAwait(false); } throw; } if (!await HandleExceptionAsync(context, exception).ConfigureAwait(false)) { throw; } } }
public async Task Handle(ConsumerPipelineContext context, IServiceProvider serviceProvider, ConsumerBehaviorHandler next) { var envelope = context.Envelopes.Single(); var operationName = $"Consuming Message on topic {envelope.Endpoint.Name}"; ISpanBuilder spanBuilder; try { var headers = envelope.Headers.ToDictionary(pair => pair.Key, pair => pair.Value.ToString()); var parentSpanCtx = GlobalTracer.Instance.Extract(BuiltinFormats.TextMap, new TextMapExtractAdapter(headers)); spanBuilder = GlobalTracer.Instance.BuildSpan(operationName); if (parentSpanCtx != null) { spanBuilder = spanBuilder.AsChildOf(parentSpanCtx); } } catch { spanBuilder = GlobalTracer.Instance.BuildSpan(operationName); } spanBuilder .WithTag(Tags.SpanKind, Tags.SpanKindConsumer) .WithTag("endpoint", envelope.Endpoint.Name); using (spanBuilder.StartActive()) { await next(context, serviceProvider); } }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public virtual async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); var sequenceReader = await _sequenceReaders .FirstOrDefaultAsync(reader => reader.CanHandleAsync(context)) .ConfigureAwait(false); if (sequenceReader == null) { await next(context).ConfigureAwait(false); return; } // Store the original envelope in case it is replaced in the GetSequence method (see ChunkSequenceReader) var originalEnvelope = context.Envelope; // Store the previous sequence since it must be added to the new one (e.g. ChunkSequence into BatchSequence) var previousSequence = context.Sequence; ISequence?sequence; // Loop to handle edge cases where the sequence gets completed between the calls to // GetSequenceAsync and AddAsync while (true) { sequence = await GetSequenceAsync(context, next, sequenceReader).ConfigureAwait(false); if (sequence == null) { return; } // Loop again if the retrieved sequence has completed already in the meanwhile // ...unless it was a new sequence, in which case it can only mean that an error // occurred in the subscriber before consuming the actual first message and it doesn't // make sense to recreate and publish once again the sequence. if (!sequence.IsPending || sequence.IsCompleting) { if (sequence.IsNew) { break; } continue; } await sequence.AddAsync(originalEnvelope, previousSequence).ConfigureAwait(false); _logger.LogMessageAddedToSequence(context.Envelope, sequence); AddSequenceTagToActivity(sequence); break; } if (sequence.IsComplete) { await AwaitOtherBehaviorIfNeededAsync(sequence).ConfigureAwait(false); // Mark the envelope as the end of the sequence only if the sequence wasn't swapped (e.g. chunk -> batch) if (sequence.Context.Sequence == null || sequence == sequence.Context.Sequence || sequence.Context.Sequence.IsCompleting || sequence.Context.Sequence.IsComplete) { context.SetIsSequenceEnd(); } _logger.LogSequenceCompleted(sequence); } }
/// <inheritdoc cref="IConsumerBehavior.HandleAsync" /> public virtual async Task HandleAsync(ConsumerPipelineContext context, ConsumerBehaviorHandler next) { Check.NotNull(context, nameof(context)); Check.NotNull(next, nameof(next)); var sequenceReader = await _sequenceReaders.FirstOrDefaultAsync(reader => reader.CanHandleAsync(context)).ConfigureAwait(false); if (sequenceReader == null) { await next(context).ConfigureAwait(false); return; } // Store the original envelope in case it is replaced in the GetSequence method (see ChunkSequenceReader) var originalEnvelope = context.Envelope; // Store the previous sequence since it must be added to the new one (e.g. ChunkSequence into BatchSequence) var previousSequence = context.Sequence; var sequence = await sequenceReader.GetSequenceAsync(context).ConfigureAwait(false); if (sequence == null) { _logger.LogWarningWithMessageInfo( IntegrationEventIds.IncompleteSequenceDiscarded, "The incomplete sequence is ignored (probably missing the first message).", context); return; } context.SetSequence(sequence, sequence.IsNew); if (sequence.IsNew) { await PublishSequenceAsync(context, next).ConfigureAwait(false); if (context.ProcessingTask != null) { MonitorProcessingTaskPrematureCompletion(context.ProcessingTask, sequence); } _logger.LogDebugWithMessageInfo( IntegrationEventIds.SequenceStarted, $"Started new {sequence.GetType().Name}.", context); } await sequence.AddAsync(originalEnvelope, previousSequence).ConfigureAwait(false); _logger.LogDebugWithMessageInfo( IntegrationEventIds.MessageAddedToSequence, $"Message added to {sequence.GetType().Name}.", context); if (sequence.IsComplete) { await AwaitOtherBehaviorIfNeededAsync(sequence).ConfigureAwait(false); // Mark the envelope as the end of the sequence only if the sequence wasn't swapped (e.g. chunk -> batch) if (sequence.Context.Sequence == null || sequence == sequence.Context.Sequence || sequence.Context.Sequence.IsCompleting || sequence.Context.Sequence.IsComplete) { context.SetIsSequenceEnd(); } _logger.LogDebugWithMessageInfo( IntegrationEventIds.SequenceCompleted, $"{sequence.GetType().Name} '{sequence.SequenceId}' completed.", context); } }