Пример #1
0
        public async Task <ResolutionEligibility> IsStreamEventEligibleForResolution(StreamEvent streamEvent, long firstPositionInStream)
        {
            var streamId    = streamEvent.IsLink ? streamEvent.Link.StreamId : streamEvent.StreamId;
            var position    = streamEvent.IsLink ? streamEvent.Link.Position : streamEvent.Position;
            var streamState = await _streamStateRepo.LoadStreamStateAsync(streamId);

            long expectedPosition = firstPositionInStream;

            if (streamState != null)
            {
                if (streamState.HasError)
                {
                    return(ResolutionEligibility.UnableStreamHasError);
                }

                if (position <= streamState.LastAttemptedPosition)
                {
                    return(ResolutionEligibility.SkippedAlreadyProcessed);
                }

                expectedPosition = streamState.LastAttemptedPosition + 1;
            }

            // Sanity check to ensure events arrive sequentially for a given stream.
            if (position != expectedPosition)
            {
                throw new InvalidOperationException($"Expected sequential event position {expectedPosition} from stream {streamEvent.StreamId} but received {streamEvent.Position}. Unable to continue.");
            }

            return(ResolutionEligibility.Eligible);
        }
Пример #2
0
        // Not thread safe.
        public async Task ManageAsync(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    while (_handlingQueue.IsEventsAvailable)
                    {
                        _awaiter.ResetHandlerCompletionSignal();

                        // Clean up finished tasks.
                        _handlerTasks.PurgeFinishedTasks();

                        // Get the next event from the queue that isn't in a parallel group already running.
                        var item = _handlingQueue.TryDequeue(_handlerTasks.Keys);
                        if (item != null)
                        {
                            // When a stream has an error there may already be subscriber events in the
                            // handling queue that have made it past the first check for errored stream state
                            // prior to deserialization. If that's the case we just ignore the event.
                            var state = await _streamStateRepo.LoadStreamStateAsync(item.SubscriberEvent.StreamId);

                            if (state == null || !state.HasError)
                            {
                                await Task.WhenAny(new[] { _awaiter.AwaitThrottleAsync(), cancellationToken.WaitHandle.AsTask() });

                                if (!cancellationToken.IsCancellationRequested)
                                {
                                    _handlerTasks.Add(item.ParallelKey, _handlerRunner.TryRunHandlerAsync(item.SubscriberEvent, cancellationToken));
                                }
                            }
                        }
                        else
                        {
                            // Events are available but none in a parallel group that is not already executing.
                            // Wait for a new event to arrive or for an event handler to complete.
                            await Task.WhenAny(new Task[] {
                                _awaiter.AwaitHandlerCompletionSignalAsync(),
                                _handlingQueue.AwaitEnqueueSignalAsync(),
                                cancellationToken.WaitHandle.AsTask()
                            });
                        }

                        if (cancellationToken.IsCancellationRequested)
                        {
                            break;
                        }
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    await Task.WhenAny(new Task[] { _handlingQueue.AwaitEnqueueSignalAsync(), cancellationToken.WaitHandle.AsTask() });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception while managing handler execution.");
                throw;
            }
        }