public When_handling_a_message_using_the_default_subscription_stream_gap_strategy()
        {
            var fixture = new Fixture()
                          .CustomizeConnectedProjectionIdentifiers();

            _projection       = fixture.Create <ConnectedProjectionIdentifier>();
            _missingPositions = fixture.CreateMany <long>(1, 10);
            var message = fixture.Create <StreamMessage>();

            var stateMock = new Mock <IProcessedStreamState>();

            stateMock
            .Setup(state => state.DetermineGapPositions(message))
            .Returns(_missingPositions);

            _processMessageFunctionStatus = "NotExecuted";

            _handlingMessage = async() => await new DefaultSubscriptionStreamGapStrategy(Mock.Of <IStreamGapStrategyConfigurationSettings>())
                               .HandleMessage(
                message,
                stateMock.Object,
                (_, token) =>
            {
                _processMessageFunctionStatus = "Executed";
                return(Task.CompletedTask);
            },
                _projection,
                fixture.Create <CancellationToken>());
        }
        public WhenMessageHandlerThrowsExceptionsDefinedByRetryPolicy()
        {
            var fixture = new Fixture()
                          .CustomizeConnectedProjectionIdentifiers();

            var exceptionSequence = fixture
                                    .CreateMany <RetryException>(2, 10)
                                    .ToArray <Exception>();

            _loggerMock           = new FakeLoggerFactory().ResolveLoggerMock <MessageHandlerWithExecutionTracking>();
            _projection           = fixture.Create <ConnectedProjectionIdentifier>();
            _handlerWithoutPolicy = new MessageHandlerWithExecutionTracking(
                _projection,
                _loggerMock.AsLogger(),
                exceptionSequence);

            _numberOfRetries          = exceptionSequence.Length;
            _numberOfExpectedAttempts = Times.Exactly(1 + _numberOfRetries);
            _initialWait = TimeSpan.FromMilliseconds(fixture.CreatePositive <int>());
            _messages    = fixture.CreateMany <StreamMessage>().ToList();

            new LinearBackOff <RetryException>(_numberOfRetries, _initialWait)
            .ApplyOn(_handlerWithoutPolicy)
            .HandleAsync(_messages, Mock.Of <IStreamGapStrategy>(), CancellationToken.None)
            .GetAwaiter()
            .GetResult();
        }
Exemple #3
0
 protected override async Task Setup()
 {
     _waitForProjection = new AutoResetEvent(false);
     _projection        = new ConnectedProjectionIdentifier(typeof(TrackHandledEventsProjection));
     await PushToStream(Fixture.Create <SomethingHappened>());
     await PushToStream(Fixture.Create <DelayWasScheduled>());
 }
Exemple #4
0
 public async Task SetErrorMessage(
     ConnectedProjectionIdentifier projection,
     Exception exception,
     CancellationToken cancellationToken)
 {
     //exception.ToString() => https://stackoverflow.com/a/2176722/412692
     await _context.SetErrorMessage(projection, exception.ToString(), cancellationToken);
 }
Exemple #5
0
        public async Task <long?> GetProjectionPosition(
            ConnectedProjectionIdentifier projection,
            CancellationToken cancellationToken)
        {
            var state = await GetProjectionState(projection, cancellationToken);

            return(state?.Position);
        }
Exemple #6
0
 public async Task UpdateProjectionDesiredState(
     ConnectedProjectionIdentifier projection,
     UserDesiredState userDesiredState,
     CancellationToken cancellationToken)
 => await _context.UpdateProjectionDesiredState(
     projection,
     userDesiredState,
     CancellationToken.None);
            public ProjectionMock(ConnectedProjectionIdentifier projectionId)
            {
                ProjectionId = projectionId;
                Projection   = new Mock <IConnectedProjection>();

                Projection
                .Setup(connectedProjection => connectedProjection.ShouldResume(It.IsAny <CancellationToken>()))
                .ReturnsAsync(() => _shouldResume);
            }
 public RegisteredConnectedProjection(
     ConnectedProjectionIdentifier id,
     ConnectedProjectionState state,
     ConnectedProjectionInfo info)
 {
     Id    = id;
     State = state;
     Info  = info;
 }
Exemple #9
0
 public async Task UpdateProjectionPosition(
     ConnectedProjectionIdentifier projection,
     long position,
     CancellationToken cancellationToken)
 => await _context
 .UpdateProjectionState(
     projection.ToString(),
     position,
     cancellationToken);
Exemple #10
0
 public MessageHandlerWithExecutionTracking(
     ConnectedProjectionIdentifier projection,
     ILogger logger,
     params Exception[] exceptionSequence)
 {
     Projection         = projection;
     Logger             = logger;
     _exceptionSequence = new Stack <Exception>(exceptionSequence.Reverse());
 }
Exemple #11
0
        public async Task <UserDesiredState?> GetProjectionDesiredState(
            ConnectedProjectionIdentifier projection,
            CancellationToken cancellationToken)
        {
            var projectionState = await GetProjectionState(projection, cancellationToken);

            return(UserDesiredState.TryParse(projectionState?.DesiredState ?? string.Empty, out var state)
                ? state
                : null);
        }
Exemple #12
0
 public async Task <ProjectionStateItem?> GetProjectionState(
     ConnectedProjectionIdentifier projection,
     CancellationToken cancellationToken)
 {
     return(await _context
            .ProjectionStates
            .AsNoTracking()
            .SingleOrDefaultAsync(
                item => item.Name == projection.ToString(),
                cancellationToken));
 }
 public ConnectedProjectionMessageHandler(
     ConnectedProjectionIdentifier projection,
     ConnectedProjectionHandler <TContext>[] handlers,
     Func <Owned <IConnectedProjectionContext <TContext> > > contextFactory,
     ILoggerFactory loggerFactory)
 {
     Projection      = projection;
     _contextFactory = contextFactory ?? throw new ArgumentNullException(nameof(contextFactory));
     _projector      = new ConnectedProjector <TContext>(Resolve.WhenEqualToHandlerMessageType(handlers));
     Logger          = loggerFactory?.CreateLogger <ConnectedProjectionMessageHandler <TContext> >() ?? throw new ArgumentNullException(nameof(loggerFactory));
 }
Exemple #14
0
        public async Task Stop(string id, CancellationToken cancellationToken)
        {
            var projection = new ConnectedProjectionIdentifier(id);

            if (!_registeredProjections.Exists(projection))
            {
                return; // throw new ArgumentException("Invalid projection Id.", nameof(projection));
            }
            await _registeredProjections
            .GetProjection(projection)
            .UpdateUserDesiredState(UserDesiredState.Stopped, cancellationToken);

            _commandBus.Queue(new Stop(projection));
        }
        protected override async Task Setup()
        {
            _waitForProjection = new AutoResetEvent(false);
            _projection        = new ConnectedProjectionIdentifier(typeof(TrackHandledEventsProjection));
            await PushToStream(Fixture.Create <SomethingHappened>());

            await ProjectionManager.Start(CancellationToken.None);

            _waitForProjection.WaitOne();
            _waitForProjection.Reset();
            await ProjectionManager.Stop(CancellationToken.None);

            await Task.Delay(500);
        }
Exemple #16
0
        public When_handling_a_message_with_a_position_that_does_follow_the_previous_message_position()
        {
            var fixture = new Fixture()
                          .CustomizeConnectedProjectionIdentifiers();

            _projectionId = fixture.Create <ConnectedProjectionIdentifier>();

            var contextMock    = new Mock <IConnectedProjectionContext <ProjectionContext> >();
            var runnerPosition = fixture
                                 .CreatePositive <long>()
                                 .WithMaximumValueOf(long.MaxValue - 100);

            contextMock
            .Setup(context => context.GetProjectionPosition(_projectionId, It.IsAny <CancellationToken>()))
            .ReturnsAsync(runnerPosition);

            var sut = new ConnectedProjectionMessageHandler <ProjectionContext>(
                _projectionId,
                Array.Empty <ConnectedProjectionHandler <ProjectionContext> >(),
                contextMock.CreateOwnedObject,
                new FakeLoggerFactory()
                );

            _message1 = fixture
                        .Build <ConfigurableStreamMessage>()
                        .With(streamMessage => streamMessage.Position, runnerPosition + 1)
                        .Create();

            _message2 = fixture
                        .Build <ConfigurableStreamMessage>()
                        .With(streamMessage => streamMessage.Position, _message1.Position + 1)
                        .Create();

            _streamGapStrategyMock = new Mock <IStreamGapStrategy>();
            _streamGapStrategyMock
            .Setup(strategy => strategy.HandleMessage(
                       It.IsAny <StreamMessage>(),
                       It.IsAny <IProcessedStreamState>(),
                       It.IsAny <Func <StreamMessage, CancellationToken, Task> >(),
                       _projectionId,
                       It.IsAny <CancellationToken>()))
            .Returns(Task.CompletedTask);

            sut.HandleAsync(
                new[] { _message1, _message2 },
                _streamGapStrategyMock.Object,
                CancellationToken.None)
            .GetAwaiter();
        }
        private void StopCatchUp(ConnectedProjectionIdentifier projection)
        {
            if (projection == null || IsCatchingUp(projection) == false)
            {
                return;
            }

            try
            {
                using (var catchUp = _projectionCatchUps[projection])
                    catchUp.Cancel();
            }
            catch (KeyNotFoundException) { }
            catch (ObjectDisposedException) { }
        }
Exemple #18
0
        public async Task HandleMessage(
            StreamMessage message,
            IProcessedStreamState state,
            Func <StreamMessage, CancellationToken, Task> executeProjectMessage,
            ConnectedProjectionIdentifier projection,
            CancellationToken cancellationToken)
        {
            if (await IsCloseToStreamEnd(message, cancellationToken))
            {
                throw new StreamGapDetectedException(state.DetermineGapPositions(message), projection);
            }

            _logger.LogWarning(
                "Expected messages at positions [{UnprocessedPositions}] were not processed for {Projection}.",
                string.Join(", ", state.DetermineGapPositions(message)),
                projection);

            await executeProjectMessage(message, cancellationToken);
        }
Exemple #19
0
        public FakeProjection(
            string id,
            Func <IEnumerable <StreamMessage>, IStreamGapStrategy, ConnectedProjectionIdentifier, CancellationToken, Task> messageHandler,
            IConnectedProjectionContext <FakeProjectionContext> context)
        {
            Id   = new ConnectedProjectionIdentifier($"{GetType().FullName}-{id}");
            Info = new ConnectedProjectionInfo(string.Empty, string.Empty);

            var messageHandlerMock = new Mock <IConnectedProjectionMessageHandler>();

            messageHandlerMock
            .SetupGet(handler => handler.Projection)
            .Returns(Id);
            messageHandlerMock
            .Setup(handler => handler.HandleAsync(It.IsAny <IEnumerable <StreamMessage> >(), It.IsAny <IStreamGapStrategy>(), It.IsAny <CancellationToken>()))
            .Returns((IEnumerable <StreamMessage> messages, IStreamGapStrategy strategy, CancellationToken ct) => messageHandler(messages, strategy, Id, ct));

            ConnectedProjectionMessageHandler = messageHandlerMock.Object;
            ContextFactory = () => new Owned <IConnectedProjectionContext <FakeProjectionContext> >(context, Mock.Of <IDisposable>());
        }
        public WhenMessageHandlerThrowsAnExceptionThatWasNotDefinedToRetryAfterRetrying()
        {
            var fixture = new Fixture()
                          .CustomizeConnectedProjectionIdentifiers();

            _exceptionSequence = new Exception[] { new RetryException(), new DoNotRetryException() };

            _loggerMock           = new FakeLoggerFactory().ResolveLoggerMock <MessageHandlerWithExecutionTracking>();
            _projection           = fixture.Create <ConnectedProjectionIdentifier>();
            _handlerWithoutPolicy = new MessageHandlerWithExecutionTracking(
                _projection,
                _loggerMock.AsLogger(),
                _exceptionSequence);

            var numberOfRetries = _exceptionSequence.Count(exception => exception is RetryException);

            _numberOfExpectedAttempts = Times.Exactly(1 + numberOfRetries);
            _initialWait = TimeSpan.FromMilliseconds(fixture.CreatePositive <int>());
            _messages    = fixture.CreateMany <StreamMessage>().ToList();

            _sut = new LinearBackOff <RetryException>(numberOfRetries, _initialWait)
                   .ApplyOn(_handlerWithoutPolicy);
        }
        public WhenMessageHandlerThrowsTheExceptionDefinedInThePolicyMoreThanTheNumberOfRetries()
        {
            var fixture = new Fixture()
                          .CustomizeConnectedProjectionIdentifiers();

            var exceptionSequence = fixture
                                    .CreateMany <RetryException>(2, 10)
                                    .ToArray <Exception>();

            _loggerMock           = new FakeLoggerFactory().ResolveLoggerMock <MessageHandlerWithExecutionTracking>();
            _projection           = fixture.Create <ConnectedProjectionIdentifier>();
            _handlerWithoutPolicy = new MessageHandlerWithExecutionTracking(
                _projection,
                _loggerMock.AsLogger(),
                exceptionSequence);

            _numberOfRetries          = exceptionSequence.Length - 1;
            _numberOfExpectedAttempts = Times.Exactly(1 + _numberOfRetries);
            _initialWait = TimeSpan.FromMilliseconds(fixture.CreatePositive <int>());
            _messages    = fixture.CreateMany <StreamMessage>().ToList();

            _sut = new LinearBackOff <RetryException>(_numberOfRetries, _initialWait)
                   .ApplyOn(_handlerWithoutPolicy);
        }
Exemple #22
0
 public StreamGapDetectedException(IEnumerable <long> missingPositions, ConnectedProjectionIdentifier projection)
     : base($"Stream does not contain messages at positions [{string.Join(',', missingPositions)}] for projection {projection}")
 {
 }
Exemple #23
0
 public async Task ClearErrorMessage(
     ConnectedProjectionIdentifier projection,
     CancellationToken cancellationToken)
 => await _context.SetErrorMessage(projection, null, cancellationToken);
 private ConnectedProjectionState GetStateFor(ConnectedProjectionIdentifier projection) => ProjectionManager
 .GetRegisteredProjections()
 .Single(connectedProjection => connectedProjection.Id == projection)
 .State;
 protected override Task Setup()
 {
     _projection        = new ConnectedProjectionIdentifier(typeof(TrackHandledEventsProjection));
     _projectionStarted = new AutoResetEvent(false);
     return(Task.CompletedTask);
 }
Exemple #26
0
 public StopCatchUp(ConnectedProjectionIdentifier projection) => Projection = projection ?? throw new ArgumentNullException(nameof(projection));
Exemple #27
0
 public Subscribe(ConnectedProjectionIdentifier projection) => Projection = projection ?? throw new ArgumentNullException(nameof(projection));
Exemple #28
0
 internal bool HasSubscription(ConnectedProjectionIdentifier projection)
 => projection != null && _handlers.ContainsKey(projection);
        public void When_creating_connected_projection_identifier_from_a_type_then_identifier_is_the_fully_qualified_name()
        {
            var identifier = new ConnectedProjectionIdentifier(typeof(ConnectedProjectionIdentifierTests));

            identifier.Should().Be("Be.Vlaanderen.Basisregisters.Projector.Tests.ConnectedProjectionIdentifierTests");
        }
 public ConnectedProjectionMessageHandlingException(Exception exception, ConnectedProjectionIdentifier projection, IProcessedStreamState?processedState)
     : base($"Error occured handling message at position: {processedState?.LastProcessedMessagePosition}", exception)
 {
     Projection     = projection;
     RunnerPosition = processedState?.LastProcessedMessagePosition ?? -1L;
 }