Exemplo n.º 1
0
        private async Task Subscribe <TContext>(IConnectedProjection <TContext> projection)
            where TContext : RunnerDbContext <TContext>
        {
            if (projection == null || _registeredProjections.IsProjecting(projection.Name))
            {
                return;
            }

            long?projectionPosition;

            using (var context = projection.ContextFactory())
                projectionPosition = await context.Value.GetRunnerPositionAsync(projection.Name, CancellationToken.None);

            if ((projectionPosition ?? -1) >= (_lastProcessedMessagePosition ?? -1))
            {
                _logger.LogInformation(
                    "Subscribing {ProjectionName} at {ProjectionPosition} to AllStream at {StreamPosition}",
                    projection.Name,
                    projectionPosition,
                    _lastProcessedMessagePosition);

                _handlers.Add(
                    projection.Name,
                    async(message, token) => await projection.ConnectedProjectionMessageHandler.HandleAsync(message, token));
            }
            else
            {
                _commandBus.Queue(new StartCatchUp(projection.Name));
            }
        }
        public async Task CatchUpAsync(CancellationToken cancellationToken)
        {
            cancellationToken.Register(() => CatchUpStopped(CatchUpStopReason.Aborted));

            try
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                _logger.LogDebug(
                    "Started catch up with paging (CatchUpPageSize: {CatchUpPageSize})",
                    _settings.CatchUpPageSize);

                long?position;
                using (var context = _projection.ContextFactory())
                    position = await context.Value.GetProjectionPosition(_projection.Id, cancellationToken);

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                _logger.LogInformation(
                    "Start catch up {Projection} at {Position}",
                    _projection.Id,
                    position);

                var page = await ReadPages(_streamStore, position, cancellationToken);

                var continueProcessing = cancellationToken.IsCancellationRequested == false;
                while (continueProcessing)
                {
                    _logger.LogDebug(
                        "Processing page of {PageSize} starting at POS {FromPosition}",
                        page.Messages.Length,
                        page.FromPosition);

                    await _projection
                    .ConnectedProjectionMessageHandler
                    .HandleAsync(
                        page.Messages,
                        _catchUpStreamGapStrategy,
                        cancellationToken);

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    if (page.IsEnd)
                    {
                        continueProcessing = false;
                    }
                    else
                    {
                        page = await page.ReadNext(cancellationToken);
                    }
                }

                CatchUpStopped(CatchUpStopReason.Finished);
            }
            catch (TaskCanceledException) { }
            catch (ConnectedProjectionMessageHandlingException e)
                when(e.InnerException is StreamGapDetectedException)
                {
                    var projection     = e.Projection;
                    var delayInSeconds = _catchUpStreamGapStrategy.Settings.RetryDelayInSeconds;

                    _logger.LogWarning(
                        "Detected gap in the message stream for catching up projection. Aborted projection {Projection} and queued restart in {GapStrategySettings.RetryDelayInSeconds} seconds.",
                        projection,
                        delayInSeconds);

                    CatchUpStopped(CatchUpStopReason.Aborted);

                    _commandBus.Queue(
                        new Restart(
                            projection,
                            TimeSpan.FromSeconds(delayInSeconds)));
                }
            catch (ConnectedProjectionMessageHandlingException exception)
            {
                _logger.LogError(
                    exception.InnerException,
                    "{Projection} catching up failed because an exception was thrown when handling the message at {Position}.",
                    exception.Projection,
                    exception.RunnerPosition);

                CatchUpStopped(CatchUpStopReason.Error);
            }
            catch (Exception exception)
            {
                _logger.LogError(
                    exception,
                    "{Projection} catching up failed because an exception was thrown",
                    _projection.Id);

                CatchUpStopped(CatchUpStopReason.Error);
            }
        }