Task <(StreamProcessorState, FailingPartitionState)> ChangePositionInFailingPartition( IStreamProcessorId streamProcessorId, StreamProcessorState oldState, PartitionId partitionId, StreamPosition newPosition, DateTimeOffset lastFailed, CancellationToken cancellationToken) =>
/// <inheritdoc/> protected override async Task <IStreamProcessorState> OnSuccessfulProcessingResult(SuccessfulProcessing successfulProcessing, StreamEvent processedEvent, IStreamProcessorState currentState) { var oldState = currentState as StreamProcessorState; var newState = new StreamProcessorState(processedEvent.Position + 1, oldState.FailingPartitions, DateTimeOffset.UtcNow); await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); return(newState); }
Task <(StreamProcessorState, FailingPartitionState)> SetFailingPartitionState( IStreamProcessorId streamProcessorId, StreamProcessorState oldState, PartitionId partitionId, uint processingAttempts, TimeSpan retryTimeout, string reason, StreamPosition position, DateTimeOffset lastFailed, CancellationToken cancellationToken) =>
async Task <StreamProcessorState> RemoveFailingPartition(IStreamProcessorId streamProcessorId, StreamProcessorState oldState, PartitionId partition, CancellationToken cancellationToken) { var newFailingPartitions = oldState.FailingPartitions; newFailingPartitions.Remove(partition); var newState = new StreamProcessorState(oldState.Position, newFailingPartitions, oldState.LastSuccessfullyProcessed); oldState.FailingPartitions.Remove(partition); await PersistNewState(streamProcessorId, newState, cancellationToken).ConfigureAwait(false); return(newState); }
/// <inheritdoc/> protected override async Task <IStreamProcessorState> ProcessEvent(StreamEvent @event, IStreamProcessorState currentState, CancellationToken cancellationToken) { var streamProcessorState = currentState as StreamProcessorState; if (streamProcessorState.FailingPartitions.Keys.Contains(@event.Partition)) { var newState = new StreamProcessorState(@event.Position + 1, streamProcessorState.FailingPartitions, streamProcessorState.LastSuccessfullyProcessed); await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); return(newState); } return(await base.ProcessEvent(@event, streamProcessorState, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Initializes a new instance of the <see cref="ScopedStreamProcessor"/> class. /// </summary> /// <param name="tenantId">The <see cref="TenantId"/>.</param> /// <param name="streamProcessorId">The <see cref="IStreamProcessorId" />.</param> /// <param name="initialState">The <see cref="StreamProcessorState" />.</param> /// <param name="processor">An <see cref="IEventProcessor" /> to process the event.</param> /// <param name="streamProcessorStates">The <see cref="IResilientStreamProcessorStateRepository" />.</param> /// <param name="eventsFromStreamsFetcher">The<see cref="ICanFetchEventsFromStream" />.</param> /// <param name="failingPartitions">The <see cref="IFailingPartitions" />.</param> /// <param name="eventsFetcherPolicy">The <see cref="IAsyncPolicyFor{T}" /> <see cref="ICanFetchEventsFromStream" />.</param> /// <param name="logger">An <see cref="ILogger" /> to log messages.</param> public ScopedStreamProcessor( TenantId tenantId, IStreamProcessorId streamProcessorId, StreamProcessorState initialState, IEventProcessor processor, IResilientStreamProcessorStateRepository streamProcessorStates, ICanFetchEventsFromPartitionedStream eventsFromStreamsFetcher, IFailingPartitions failingPartitions, IAsyncPolicyFor <ICanFetchEventsFromStream> eventsFetcherPolicy, ILogger <ScopedStreamProcessor> logger) : base(tenantId, streamProcessorId, initialState, processor, eventsFromStreamsFetcher, eventsFetcherPolicy, logger) { _streamProcessorStates = streamProcessorStates; _failingPartitions = failingPartitions; }
/// <inheritdoc/> public async Task <IStreamProcessorState> AddFailingPartitionFor( IStreamProcessorId streamProcessorId, StreamProcessorState oldState, StreamPosition failedPosition, PartitionId partition, DateTimeOffset retryTime, string reason, CancellationToken cancellationToken) { var failingPartition = new FailingPartitionState(failedPosition, retryTime, reason, 1, DateTimeOffset.UtcNow); var failingPartitions = new Dictionary <PartitionId, FailingPartitionState>(oldState.FailingPartitions) { [partition] = failingPartition }; var newState = new StreamProcessorState(failedPosition + 1, failingPartitions, oldState.LastSuccessfullyProcessed); await PersistNewState(streamProcessorId, newState, cancellationToken).ConfigureAwait(false); return(newState); }
/// <inheritdoc/> public async Task <IStreamProcessorState> CatchupFor( IStreamProcessorId streamProcessorId, StreamProcessorState streamProcessorState, CancellationToken cancellationToken) { if (streamProcessorState.FailingPartitions.Count > 0) { streamProcessorState = (await _streamProcessorStates.TryGetFor(streamProcessorId, cancellationToken) .ConfigureAwait(false)).Result as StreamProcessorState; } var failingPartitionsList = streamProcessorState.FailingPartitions.ToList(); foreach (var kvp in failingPartitionsList) { var partition = kvp.Key; var failingPartitionState = kvp.Value; if (ShouldRetryProcessing(failingPartitionState)) { while (ShouldProcessNextEventInPartition(failingPartitionState.Position, streamProcessorState.Position)) { var tryGetEvent = await _eventsFetcherPolicy.Execute( cancellationToken => _eventsFromStreamsFetcher.FetchInPartition(partition, failingPartitionState.Position, cancellationToken), cancellationToken).ConfigureAwait(false); if (!tryGetEvent.Success) { break; } var streamEvent = tryGetEvent.Result; if (streamEvent.Partition != partition) { throw new StreamEventInWrongPartition(streamEvent, partition); } if (!ShouldProcessNextEventInPartition(streamEvent.Position, streamProcessorState.Position)) { break; } if (!ShouldRetryProcessing(failingPartitionState)) { break; } var processingResult = await RetryProcessingEvent( failingPartitionState, streamEvent.Event, partition, cancellationToken).ConfigureAwait(false); if (processingResult.Succeeded) { (streamProcessorState, failingPartitionState) = await ChangePositionInFailingPartition( streamProcessorId, streamProcessorState, partition, streamEvent.Position + 1, failingPartitionState.LastFailed, cancellationToken).ConfigureAwait(false); } else if (processingResult.Retry) { (streamProcessorState, failingPartitionState) = await SetFailingPartitionState( streamProcessorId, streamProcessorState, partition, failingPartitionState.ProcessingAttempts + 1, processingResult.RetryTimeout, processingResult.FailureReason, streamEvent.Position, DateTimeOffset.UtcNow, cancellationToken).ConfigureAwait(false); } else { (streamProcessorState, failingPartitionState) = await SetFailingPartitionState( streamProcessorId, streamProcessorState, partition, failingPartitionState.ProcessingAttempts + 1, DateTimeOffset.MaxValue, processingResult.FailureReason, streamEvent.Position, DateTimeOffset.UtcNow, cancellationToken).ConfigureAwait(false); } } if (ShouldRetryProcessing(failingPartitionState)) { streamProcessorState = await RemoveFailingPartition(streamProcessorId, streamProcessorState, partition, cancellationToken).ConfigureAwait(false); } } } return(streamProcessorState); }