From fa24e48d5cf03e5f8c8b8422f2ec1f95fc36d8c4 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Thu, 19 Oct 2023 14:50:54 +0200 Subject: [PATCH] Adjusted Async projection test with IoC injection to remove flakiness The issue was in the Daemon run both as hosted service and then manually to wait for shards. --- docs/events/projections/ioc.md | 22 ++++++---- .../projections_with_IoC_services.cs | 43 +++++++++---------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/docs/events/projections/ioc.md b/docs/events/projections/ioc.md index 97bb97412df..e9bdaf7a6fc 100644 --- a/docs/events/projections/ioc.md +++ b/docs/events/projections/ioc.md @@ -16,7 +16,7 @@ Let's say you have a custom aggregation projection like this one below that need ```cs -public class ProductProjection : CustomProjection +public class ProductProjection: CustomProjection { private readonly IPriceLookup _lookup; @@ -28,10 +28,14 @@ public class ProductProjection : CustomProjection ProjectionName = "Product"; } - public override ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSlice slice, CancellationToken cancellation, - ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline) + public override ValueTask ApplyChangesAsync( + DocumentSessionBase session, + EventSlice slice, + CancellationToken cancellation, + ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline + ) { - slice.Aggregate ??= new Product{Id = slice.Id}; + slice.Aggregate ??= new Product { Id = slice.Id }; foreach (var data in slice.AllData()) { @@ -52,7 +56,7 @@ public class ProductProjection : CustomProjection } } ``` -snippet source | anchor +snippet source | anchor Now, we *want* to use this projection at runtime within Marten, and need to register the projection @@ -73,12 +77,14 @@ using var host = await Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() opts.DatabaseSchemaName = "ioc"; }) // Note that this is chained after the call to AddMarten() - .AddProjectionWithServices(ProjectionLifecycle.Inline, ServiceLifetime.Singleton); - + .AddProjectionWithServices( + ProjectionLifecycle.Inline, + ServiceLifetime.Singleton + ); }) .StartAsync(); ``` -snippet source | anchor +snippet source | anchor Note that we're having to explicitly specify the projection lifecycle for the projection used within diff --git a/src/EventSourcingTests/Projections/projections_with_IoC_services.cs b/src/EventSourcingTests/Projections/projections_with_IoC_services.cs index 932cb07cc7f..c4ef209f2d1 100644 --- a/src/EventSourcingTests/Projections/projections_with_IoC_services.cs +++ b/src/EventSourcingTests/Projections/projections_with_IoC_services.cs @@ -3,10 +3,7 @@ using System.Threading.Tasks; using JasperFx.Core; using Marten; -using Marten.Events; using Marten.Events.Aggregation; -using Marten.Events.Daemon; -using Marten.Events.Daemon.Resiliency; using Marten.Events.Projections; using Marten.Internal.Sessions; using Marten.Testing.Harness; @@ -17,7 +14,6 @@ namespace EventSourcingTests.Projections; - [Collection("ioc")] public class projections_with_IoC_services { @@ -37,8 +33,10 @@ public async Task use_projection_as_singleton_and_inline() opts.DatabaseSchemaName = "ioc"; }) // Note that this is chained after the call to AddMarten() - .AddProjectionWithServices(ProjectionLifecycle.Inline, ServiceLifetime.Singleton); - + .AddProjectionWithServices( + ProjectionLifecycle.Inline, + ServiceLifetime.Singleton + ); }) .StartAsync(); @@ -46,20 +44,21 @@ public async Task use_projection_as_singleton_and_inline() var store = host.Services.GetRequiredService(); - using var session = store.LightweightSession(); - var streamId = session.Events.StartStream(new ProductRegistered("Ankle Socks", "Socks")).Id; + await using var session = store.LightweightSession(); + var streamId = session.Events.StartStream( + new ProductRegistered("Ankle Socks", "Socks") + ).Id; await session.SaveChangesAsync(); var product = await session.LoadAsync(streamId); product.Price.ShouldBeGreaterThan(0); product.Name.ShouldBe("Ankle Socks"); - } [Fact] public async Task use_projection_as_singleton_and_async() { - using var host = await Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() + using var host = await Host.CreateDefaultBuilder() .ConfigureServices(services => { services.AddSingleton(); @@ -68,16 +67,15 @@ public async Task use_projection_as_singleton_and_async() { opts.Connection(ConnectionSource.ConnectionString); opts.DatabaseSchemaName = "ioc"; + opts.Projections.DaemonLockId = 99123; }) - .AddAsyncDaemon(DaemonMode.Solo) .AddProjectionWithServices(ProjectionLifecycle.Async, ServiceLifetime.Singleton); - }).StartAsync(); var store = host.Services.GetRequiredService(); await store.Advanced.Clean.CompletelyRemoveAllAsync(); - using var session = store.LightweightSession(); + await using var session = store.LightweightSession(); var streamId = session.Events.StartStream(new ProductRegistered("Ankle Socks", "Socks")).Id; await session.SaveChangesAsync(); @@ -87,9 +85,9 @@ public async Task use_projection_as_singleton_and_async() await daemon.Tracker.WaitForShardState("Product:All", 1); var product = await session.LoadAsync(streamId); + product.ShouldNotBeNull(); product.Price.ShouldBeGreaterThan(0); product.Name.ShouldBe("Ankle Socks"); - } [Fact] @@ -105,23 +103,20 @@ public async Task use_projection_as_scoped_and_inline() opts.Connection(ConnectionSource.ConnectionString); opts.DatabaseSchemaName = "ioc"; }).AddProjectionWithServices(ProjectionLifecycle.Inline, ServiceLifetime.Scoped); - }).StartAsync(); var store = host.Services.GetRequiredService(); - using var session = store.LightweightSession(); + await using var session = store.LightweightSession(); var streamId = session.Events.StartStream(new ProductRegistered("Ankle Socks", "Socks")).Id; await session.SaveChangesAsync(); var product = await session.LoadAsync(streamId); product.Price.ShouldBeGreaterThan(0); product.Name.ShouldBe("Ankle Socks"); - } } - public interface IPriceLookup { double PriceFor(string category); @@ -148,7 +143,7 @@ public record ProductRegistered(string Name, string Category); #region sample_ProductProjection -public class ProductProjection : CustomProjection +public class ProductProjection: CustomProjection { private readonly IPriceLookup _lookup; @@ -160,10 +155,14 @@ public ProductProjection(IPriceLookup lookup) ProjectionName = "Product"; } - public override ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSlice slice, CancellationToken cancellation, - ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline) + public override ValueTask ApplyChangesAsync( + DocumentSessionBase session, + EventSlice slice, + CancellationToken cancellation, + ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline + ) { - slice.Aggregate ??= new Product{Id = slice.Id}; + slice.Aggregate ??= new Product { Id = slice.Id }; foreach (var data in slice.AllData()) {