Beispiel #1
0
        public async Task OnError_Continue_prevents_aggregator_exceptions_from_stopping_catchup()
        {
            var count           = 0;
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            var projector = new BalanceProjector()
                            .Pipeline(async(projection, batch, next) =>
            {
                Interlocked.Increment(ref count);
                if (count < 20)
                {
                    throw new Exception("oops");
                }
                await next(projection, batch);
            }).Trace();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate().Trace(),
                                            batchSize: 50);

            catchup.Subscribe(projector,
                              projectionStore.AsHandler(),
                              onError: e => e.Continue());

            await catchup.RunSingleBatch();

            projectionStore.Count().Should().Be(31);
        }
        public async Task Distributed_catchups_can_store_a_cursor_per_partition()
        {
            var cursorStore = new InMemoryProjectionStore <ICursor <int> >(_ => Cursor.New <int>());

            var aggregator = Aggregator.Create <Projection <HashSet <string>, int>, string>((p, xs) =>
            {
                if (p.Value == null)
                {
                    p.Value = new HashSet <string>();
                }

                foreach (var x in xs)
                {
                    p.Value.Add(x);
                }
            }).Trace();

            var catchup = partitionedStream
                          .DistributeAmong(partitions,
                                           batchSize: 73,
                                           cursorPerPartition: cursorStore.Trace().AsHandler());

            catchup.Subscribe(aggregator);

            await catchup.RunUntilCaughtUp();

            cursorStore.Count().Should().Be(26);
            Enumerable.Range(1, 26).ToList().ForEach(i =>
            {
                cursorStore.Should().Contain(c => c.Position == i * 100);
            });
        }
Beispiel #3
0
        public async Task RunSingleBatch_throws_when_an_aggregator_throws_an_exception()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            var projector = new BalanceProjector()
                            .Pipeline(async(projection, batch, next) =>
            {
                if (projectionStore.Count() >= 30)
                {
                    throw new Exception("oops");
                }
                await next(projection, batch);
            });

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 50);

            catchup.Subscribe(projector, projectionStore);

            Action runSingleBatch = () => catchup.RunSingleBatch().Wait();

            runSingleBatch.ShouldThrow <Exception>()
            .And
            .Message
            .Should()
            .Contain("oops");
        }
        public async Task OnError_Continue_prevents_aggregator_exceptions_from_stopping_catchup()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();
            var count           = 0;

            var projector = new BalanceProjector()
                            .Pipeline(async(projection, batch, next) =>
            {
                Interlocked.Increment(ref count);
                Console.WriteLine(count);
                if (count < 49)
                {
                    Throw();
                }
                await next(projection, batch);
            }).Trace();

            var catchup = StreamCatchup.Create(stream.Trace(),
                                               batchSize: 50);

            catchup.Subscribe(projector,
                              projectionStore.AsHandler(),
                              onError: e => e.Continue());

            await catchup.RunUntilCaughtUp();

            projectionStore.Count().Should().Be(1);
            projectionStore.Single().CursorPosition.Should().Be(1);
        }
Beispiel #5
0
        public async Task Catchup_upstream_batch_size_can_be_specified()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 20);

            catchup.Subscribe(new BalanceProjector(), projectionStore);

            await catchup.RunSingleBatch();

            projectionStore.Count()
            .Should()
            .Be(20);
        }
        public async Task Catchup_can_use_a_sequence_of_keys_to_traverse_all_aggregates()
        {
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate());
            catchup.Subscribe(new BalanceProjector(), projectionStore);
            await catchup.RunSingleBatch();

            projectionStore.Sum(b => b.Balance)
                           .Should()
                           .Be(100);
            projectionStore.Count()
                           .Should()
                           .Be(100);
        }
        public async Task Catchup_can_traverse_all_events()
        {
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();
            store.WriteEvents(streamId, 999);
            var catchup = StreamCatchup.Create(stream);
            catchup.Subscribe(new BalanceProjector(), projectionStore);
            await catchup.RunSingleBatch();

            projectionStore.Sum(b => b.Balance)
                           .Should()
                           .Be(1000);
            projectionStore.Count()
                           .Should()
                           .Be(1);
        }
Beispiel #8
0
        public async Task Catchup_can_use_a_sequence_of_keys_to_traverse_all_aggregates()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate());

            catchup.Subscribe(new BalanceProjector(), projectionStore);
            await catchup.RunSingleBatch();

            projectionStore.Sum(b => b.Balance)
            .Should()
            .Be(100);
            projectionStore.Count()
            .Should()
            .Be(100);
        }
        public async Task Catchup_can_traverse_all_events()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            store.WriteEvents(streamId, 999);
            var catchup = StreamCatchup.Create(stream);

            catchup.Subscribe(new BalanceProjector(), projectionStore);
            await catchup.RunSingleBatch();

            projectionStore.Sum(b => b.Balance)
            .Should()
            .Be(1000);
            projectionStore.Count()
            .Should()
            .Be(1);
        }
        public async Task When_one_batch_is_running_a_second_call_to_RunSingleBatch_will_not_do_anything()
        {
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();

            var catchup = StreamCatchup.Create(stream, batchCount: 1);
            catchup.Subscribe(new BalanceProjector()
                                  .Pipeline(async (projection, batch, next) =>
                                  {
                                      await Task.Delay(500);
                                      await next(projection, batch);
                                  }), projectionStore);

            await Task.WhenAll(catchup.RunSingleBatch(), catchup.RunSingleBatch());

            projectionStore.Count()
                           .Should()
                           .Be(1);
        }
        public async Task When_one_batch_is_running_a_second_call_to_RunSingleBatch_will_not_do_anything()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            var catchup = StreamCatchup.Create(stream, batchSize: 1);

            catchup.Subscribe(new BalanceProjector()
                              .Pipeline(async(projection, batch, next) =>
            {
                await Task.Delay(500);
                await next(projection, batch);
            }), projectionStore);

            await Task.WhenAll(catchup.RunSingleBatch(), catchup.RunSingleBatch());

            projectionStore.Count()
            .Should()
            .Be(1);
        }
Beispiel #12
0
        public async Task Catchup_RunUntilCaughtUp_runs_until_the_stream_has_no_more_results()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 10);

            catchup.Subscribe(new BalanceProjector(), projectionStore);

            TaskScheduler.UnobservedTaskException += (sender, args) => Console.WriteLine(args.Exception);

            await catchup.RunUntilCaughtUp();

            projectionStore.Sum(b => b.Balance)
            .Should()
            .Be(100);
            projectionStore.Count()
            .Should()
            .Be(100);
        }
Beispiel #13
0
        public async Task Stream_traversal_can_continue_from_upstream_cursor_that_was_returned_by_RunSingleBatch()
        {
            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 50);

            catchup.Subscribe(new BalanceProjector(), new InMemoryProjectionStore <BalanceProjection>());

            var cursor = await catchup.RunSingleBatch();

            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

            catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), cursor);
            catchup.Subscribe(new BalanceProjector(), projectionStore);

            await catchup.RunSingleBatch();

            projectionStore.Count()
            .Should()
            .Be(50);
        }
Beispiel #14
0
        public async Task Catchup_starting_cursor_can_be_specified()
        {
            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 50);

            catchup.Subscribe(new BalanceProjector(), new InMemoryProjectionStore <BalanceProjection>());

            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();
            var updatedStreams  = streamSource.StreamPerAggregate();
            var cursor          = updatedStreams.NewCursor();

            cursor.AdvanceTo("50");
            catchup = StreamCatchup.All(updatedStreams, cursor);
            catchup.Subscribe(new BalanceProjector(), projectionStore);

            await catchup.RunSingleBatch();

            projectionStore.Count()
            .Should()
            .Be(50);
        }
        public async Task When_an_aggregation_fails_then_the_projection_is_not_updated()
        {
            var projections = new InMemoryProjectionStore<BalanceProjection>();
            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate().Trace());

            // subscribe a flaky projector
            catchup.Subscribe(new BalanceProjector()
                                  .Pipeline(async (projection, batch, next) =>
                                  {
                                      bool shouldThrow = true; // declared outside to nudge the compiler into inferring the correct .Pipeline overload
                                      if (shouldThrow)
                                      {
                                          throw new Exception("oops");
                                      }
                                      await next(projection, batch);
                                  }),
                              projections.AsHandler(),
                              e => e.Continue());

            await catchup.RunSingleBatch();

            projections.Count().Should().Be(0);
        }
Beispiel #16
0
        public async Task When_an_aggregation_fails_then_the_projection_is_not_updated()
        {
            var projections = new InMemoryProjectionStore <BalanceProjection>();
            var catchup     = StreamCatchup.All(streamSource.StreamPerAggregate().Trace());

            // subscribe a flaky projector
            catchup.Subscribe(new BalanceProjector()
                              .Pipeline(async(projection, batch, next) =>
            {
                bool shouldThrow = true;                       // declared outside to nudge the compiler into inferring the correct .Pipeline overload
                if (shouldThrow)
                {
                    throw new Exception("oops");
                }
                await next(projection, batch);
            }),
                              projections.AsHandler(),
                              e => e.Continue());

            await catchup.RunSingleBatch();

            projections.Count().Should().Be(0);
        }
        public async Task OnError_Continue_prevents_aggregator_exceptions_from_stopping_catchup()
        {
            var count = 0;
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();

            var projector = new BalanceProjector()
                .Pipeline(async (projection, batch, next) =>
                {
                    Interlocked.Increment(ref count);
                    if (count < 20)
                    {
                        throw new Exception("oops");
                    }
                    await next(projection, batch);
                }).Trace();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate().Trace(),
                                            batchSize: 50);

            catchup.Subscribe(projector,
                              projectionStore.AsHandler(),
                              onError: e => e.Continue());

            await catchup.RunSingleBatch();

            projectionStore.Count().Should().Be(31);
        }
        public async Task Stream_traversal_can_continue_from_upstream_cursor_that_was_returned_by_RunSingleBatch()
        {
            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 50);
            catchup.Subscribe(new BalanceProjector(), new InMemoryProjectionStore<BalanceProjection>());

            var cursor = await catchup.RunSingleBatch();

            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();
            catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), cursor);
            catchup.Subscribe(new BalanceProjector(), projectionStore);

            await catchup.RunSingleBatch();

            projectionStore.Count()
                           .Should()
                           .Be(50);
        }
        public async Task OnError_Continue_prevents_aggregator_exceptions_from_stopping_catchup()
        {
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();
            var count = 0;
        
            var projector = new BalanceProjector()
                .Pipeline(async (projection, batch, next) =>
                {
                    Interlocked.Increment(ref count);
                    Console.WriteLine(count);
                    if (count < 49)
                    {
                        Throw();
                    }
                    await next(projection, batch);
                }).Trace();

            var catchup = StreamCatchup.Create(stream.Trace(),
                                               batchCount: 50);

            catchup.Subscribe(projector, 
                projectionStore.AsHandler(), 
                onError: e => e.Continue());

            await catchup.RunUntilCaughtUp();

            projectionStore.Count().Should().Be(1);
            projectionStore.Single().CursorPosition.Should().Be(1);
        }
        public async Task Catchup_RunUntilCaughtUp_runs_until_the_stream_has_no_more_results()
        {
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 10);
            catchup.Subscribe(new BalanceProjector(), projectionStore);

            TaskScheduler.UnobservedTaskException += (sender, args) => Console.WriteLine(args.Exception);

            await catchup.RunUntilCaughtUp();

            projectionStore.Sum(b => b.Balance)
                           .Should()
                           .Be(100);
            projectionStore.Count()
                           .Should()
                           .Be(100);
        }
        public async Task RunSingleBatch_throws_when_an_aggregator_throws_an_exception()
        {
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();

            var projector = new BalanceProjector()
                .Pipeline(async (projection, batch, next) =>
                {
                    if (projectionStore.Count() >= 30)
                    {
                        throw new Exception("oops");
                    }
                    await next(projection, batch);
                });

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 50);
            catchup.Subscribe(projector, projectionStore);

            Action runSingleBatch = () => catchup.RunSingleBatch().Wait();

            runSingleBatch.ShouldThrow<Exception>()
                          .And
                          .Message
                          .Should()
                          .Contain("oops");
        }
        public async Task Distributed_catchups_can_store_a_cursor_per_partition()
        {
            var cursorStore = new InMemoryProjectionStore<ICursor<int>>(_ => Cursor.New<int>());

            var aggregator = Aggregator.Create<Projection<HashSet<string>, int>, string>((p, xs) =>
            {
                if (p.Value == null)
                {
                    p.Value = new HashSet<string>();
                }

                foreach (var x in xs)
                {
                    p.Value.Add(x);
                }
            }).Trace();

            var catchup = partitionedStream
                .DistributeAmong(partitions,
                                 batchSize: 73,
                                 cursorPerPartition: cursorStore.Trace().AsHandler());

            catchup.Subscribe(aggregator);

            await catchup.RunUntilCaughtUp();

            cursorStore.Count().Should().Be(26);
            Enumerable.Range(1, 26).ToList().ForEach(i =>
            {
                cursorStore.Should().Contain(c => c.Position == i*100);
            });
        }
        public async Task Catchup_upstream_batch_size_can_be_specified()
        {
            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 20);
            catchup.Subscribe(new BalanceProjector(), projectionStore);

            await catchup.RunSingleBatch();

            projectionStore.Count()
                           .Should()
                           .Be(20);
        }
        public async Task Catchup_starting_cursor_can_be_specified()
        {
            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate(), batchSize: 50);
            catchup.Subscribe(new BalanceProjector(), new InMemoryProjectionStore<BalanceProjection>());

            var projectionStore = new InMemoryProjectionStore<BalanceProjection>();
            var updatedStreams = streamSource.StreamPerAggregate();
            var cursor = updatedStreams.NewCursor();
            cursor.AdvanceTo("50");
            catchup = StreamCatchup.All(updatedStreams, cursor);
            catchup.Subscribe(new BalanceProjector(), projectionStore);

            await catchup.RunSingleBatch();

            projectionStore.Count()
                           .Should()
                           .Be(50);
        }