From 1134aa83887aab8b23a1201a61f33b199f29d164 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Thu, 3 Mar 2022 08:35:27 +0100 Subject: [PATCH] Updated EventStoreDB samples documentation --- .../EventStoreDBSubscriptionToAll.cs | 3 +- Sample/EventStoreDB/ECommerce/ECommerce.sln | 10 +++++ Sample/EventStoreDB/ECommerce/README.md | 17 ++++---- .../ECommerce/docker/docker-compose.yml | 40 +++++++++---------- Sample/EventStoreDB/Simple/ECommerce.sln | 12 ++++++ Sample/EventStoreDB/Simple/README.md | 8 ++-- .../Simple/docker/docker-compose.yml | 36 +++++++++-------- 7 files changed, 74 insertions(+), 52 deletions(-) diff --git a/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs b/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs index 3ef72cfb1..cd023dbad 100644 --- a/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs +++ b/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs @@ -51,8 +51,9 @@ ILogger logger public async Task SubscribeToAll(EventStoreDBSubscriptionToAllOptions subscriptionOptions, CancellationToken ct) { + // see: https://github.com/dotnet/runtime/issues/36063 await Task.Yield(); - + this.subscriptionOptions = subscriptionOptions; cancellationToken = ct; diff --git a/Sample/EventStoreDB/ECommerce/ECommerce.sln b/Sample/EventStoreDB/ECommerce/ECommerce.sln index bf6815900..e8f3aee7c 100644 --- a/Sample/EventStoreDB/ECommerce/ECommerce.sln +++ b/Sample/EventStoreDB/ECommerce/ECommerce.sln @@ -22,6 +22,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Testing", "..\..\..\Co EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.WebApi", "..\..\..\Core.WebApi\Core.WebApi.csproj", "{921935A7-E757-45C0-913B-65892EFFE920}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{94838965-E83B-4DA3-9533-E065E3E8718C}" + ProjectSection(SolutionItems) = preProject + docker\docker-compose.yml = docker\docker-compose.yml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{05FA325E-387E-4297-9AAA-8BBDFBBB9B13}" + ProjectSection(SolutionItems) = preProject + README.md = README.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/Sample/EventStoreDB/ECommerce/README.md b/Sample/EventStoreDB/ECommerce/README.md index c2a126d73..987728987 100644 --- a/Sample/EventStoreDB/ECommerce/README.md +++ b/Sample/EventStoreDB/ECommerce/README.md @@ -37,17 +37,16 @@ It uses: - Most of the write model infrastructure was reused from other samples, - Added new project `Core.EventStoreDB` for specific EventStoreDB code, -- Added [EventStoreDBRepository](./Core/Core.EventStoreDB/Repository/EventStoreDBRepository.cs) repository to load and store aggregate state, -- Added separate [IProjection](./Core/Core/Projections/IProjection.cs) interface to handle the same way stream aggregation and materialised projections, +- Added [EventStoreDBRepository](../../../Core/Core.EventStoreDB/Repository/EventStoreDBRepository.cs) repository to load and store aggregate state, +- Added separate [IProjection](../../../Core/Projections/IProjection.cs) interface to handle the same way stream aggregation and materialised projections, - Thanks to that added dedicated [AggregateStream](./Core/Core.EventStoreDB/Events/AggregateStreamExtensions.cs#L12) method for stream aggregation - See [sample Aggregate](./Carts/Carts/Carts/Cart.cs) ## Read Model - Read models are rebuilt with eventual consistency using subscribe to all EventStoreDB feature, -- Added hosted service [SubscribeToAllBackgroundWorker](./Core/Core.EventStoreDB/Subscriptions/SubscribeToAllBackgroundWorker.cs) to handle subscribing to all. It handles checkpointing and simple retries if the connection was dropped. -- Added [ISubscriptionCheckpointRepository](./Core/Core.EventStoreDB/Subscriptions/ISubscriptionCheckpointRepository.cs) for handling Subscription checkpointing. -- Added checkpointing to EventStoreDB stream with [EventStoreDBSubscriptionCheckpointRepository](./Core/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionCheckpointRepository.cs) and dummy in-memory checkpointer [InMemorySubscriptionCheckpointRepository](./Core/Core.EventStoreDB/Subscriptions/InMemorySubscriptionCheckpointRepository.cs), -- Added [MartenExternalProjection](./Core/Core.Marten/ExternalProjections/MartenExternalProjection.cs) as a sample how to project with [`left-fold`](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) into external storage. Another (e.g. ElasticSearch, EntityFramework) can be implemented the same way. +- Uses hosted service [EventStoreDBSubscriptionToAll](../../../Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs) to handle subscribing to all. It handles checkpointing and simple retries if the connection was dropped. +- Uses checkpointing to EventStoreDB stream with [EventStoreDBSubscriptionCheckpointRepository](../../../Core/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionCheckpointRepository.cs) and dummy in-memory checkpointer [InMemorySubscriptionCheckpointRepository](./Core/Core.EventStoreDB/Subscriptions/InMemorySubscriptionCheckpointRepository.cs), +- Uses [MartenExternalProjection](../../../Core/Core.Marten/ExternalProjections/MartenExternalProjection.cs) as a sample how to project with [`left-fold`](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) into external storage. Another (e.g. ElasticSearch, EntityFramework) can be implemented the same way. ## Tests - Added sample of unit testing in [`Carts.Tests`](./Carts/Carts.Tests): @@ -57,9 +56,9 @@ It uses: - [API integration tests](./Carts/Carts.Api.Tests/Carts/InitializingCart/InitializeCartTests.cs) ## Other -- Added [EventTypeMapper](./Core/Core/Events/EventTypeMapper.cs) class to allow both convention-based mapping (by the .NET type name) and custom to handle event versioning, -- Added [StreamNameMapper](./Core/Core/Events/StreamNameMapper.cs) class for convention-based id (and optional tenant) mapping based on the stream type and module, -- IoC [registration helpers for EventStoreDB configuration](./Core/Core.EventStoreDB/Config.cs), +- Uses [EventTypeMapper](../../../Core/Events/EventTypeMapper.cs) class to allow both convention-based mapping (by the .NET type name) and custom to handle event versioning, +- Uses [StreamNameMapper](../../../Core/Events/StreamNameMapper.cs) class for convention-based id (and optional tenant) mapping based on the stream type and module, +- IoC [registration helpers for EventStoreDB configuration](../../../Core/Core.EventStoreDB/Config.cs), ## Trivia diff --git a/Sample/EventStoreDB/ECommerce/docker/docker-compose.yml b/Sample/EventStoreDB/ECommerce/docker/docker-compose.yml index 7eb850c11..71907f63c 100644 --- a/Sample/EventStoreDB/ECommerce/docker/docker-compose.yml +++ b/Sample/EventStoreDB/ECommerce/docker/docker-compose.yml @@ -20,33 +20,33 @@ services: - "${PGADMIN_PORT:-5050}:80" networks: - postgres - + ####################################################### # EventStoreDB ####################################################### eventstore.db: - image: eventstore/eventstore:21.2.0-buster-slim + image: eventstore/eventstore:21.10.1-buster-slim + # use this image if you're running ARM-based proc like Apple M1 + # image: ghcr.io/eventstore/eventstore:21.10.0-alpha-arm64v8 environment: - - EVENTSTORE_CLUSTER_SIZE=1 - - EVENTSTORE_RUN_PROJECTIONS=All - - EVENTSTORE_START_STANDARD_PROJECTIONS=true - - EVENTSTORE_EXT_TCP_PORT=1113 - - EVENTSTORE_EXT_HTTP_PORT=2113 - - EVENTSTORE_INSECURE=true - - EVENTSTORE_ENABLE_EXTERNAL_TCP=true - - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true + - EVENTSTORE_CLUSTER_SIZE=1 + - EVENTSTORE_RUN_PROJECTIONS=All + - EVENTSTORE_START_STANDARD_PROJECTIONS=true + - EVENTSTORE_EXT_TCP_PORT=1113 + - EVENTSTORE_HTTP_PORT=2113 + - EVENTSTORE_INSECURE=true + - EVENTSTORE_ENABLE_EXTERNAL_TCP=true + - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true ports: - - '1113:1113' - - '2113:2113' + - '1113:1113' + - '2113:2113' volumes: - - type: volume - source: eventstore-volume-data - target: /var/lib/eventstore - - type: volume - source: eventstore-volume-logs - target: /var/log/eventstore - networks: - - eventstore.db + - type: volume + source: eventstore-volume-data + target: /var/lib/eventstore + - type: volume + source: eventstore-volume-logs + target: /var/log/eventstore networks: postgres: diff --git a/Sample/EventStoreDB/Simple/ECommerce.sln b/Sample/EventStoreDB/Simple/ECommerce.sln index 7ea93879c..333ac5b59 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.sln +++ b/Sample/EventStoreDB/Simple/ECommerce.sln @@ -19,6 +19,13 @@ ProjectSection(SolutionItems) = preProject README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.EventStoreDB", "..\..\..\Core.EventStoreDB\Core.EventStoreDB.csproj", "{8D0F5E6A-F460-4FE0-BD5E-02356D7D56CB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{88584BD6-A70F-464D-9EFD-609C5E1C10DE}" + ProjectSection(SolutionItems) = preProject + docker\docker-compose.yml = docker\docker-compose.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +34,7 @@ Global GlobalSection(NestedProjects) = preSolution {AE9175ED-054C-46F6-A91D-0F2691BD935B} = {1F491B11-2201-4616-976F-A3012D95BD9C} {3C69FDAF-20C4-49C4-A648-C0AD8958CB3D} = {1F491B11-2201-4616-976F-A3012D95BD9C} + {8D0F5E6A-F460-4FE0-BD5E-02356D7D56CB} = {1F491B11-2201-4616-976F-A3012D95BD9C} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {7AA17923-7368-449B-95E6-5A64C1FAF4B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -53,5 +61,9 @@ Global {3DF5E171-72BD-4129-B66C-5428029CF932}.Debug|Any CPU.Build.0 = Debug|Any CPU {3DF5E171-72BD-4129-B66C-5428029CF932}.Release|Any CPU.ActiveCfg = Release|Any CPU {3DF5E171-72BD-4129-B66C-5428029CF932}.Release|Any CPU.Build.0 = Release|Any CPU + {8D0F5E6A-F460-4FE0-BD5E-02356D7D56CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D0F5E6A-F460-4FE0-BD5E-02356D7D56CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D0F5E6A-F460-4FE0-BD5E-02356D7D56CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D0F5E6A-F460-4FE0-BD5E-02356D7D56CB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Sample/EventStoreDB/Simple/README.md b/Sample/EventStoreDB/Simple/README.md index 356053b87..6eb406c87 100644 --- a/Sample/EventStoreDB/Simple/README.md +++ b/Sample/EventStoreDB/Simple/README.md @@ -33,7 +33,6 @@ It uses: - Command handlers are defined as static methods in the same file as command definition. Usually, they change together. They are pure functions that take command and/or state and create new events based on the business logic. See sample [Adding Product Item to ShoppingCart](./ECommerce/ShoppingCarts/AddingProductItem/AddProductItemToShoppingCart.cs#L25). This example also shows that you can inject external services to handlers if needed. - [Added syntax for self-documenting command handlers registration](./ECommerce/ShoppingCarts/Configuration.cs#L22). See the details of registration in [CommandHandlerExtensions](./ECommerce.Core/Commands/CommandHandler.cs). They differentiate case when [a new entity/stream is created](./ECommerce.Core/Commands/CommandHandler.cs#L12) from the [update case](./ECommerce.CoreECommerce.Core/Commands/CommandHandler.cs#L26). Update has to support optimistic concurrency. Added also [Command Handlers Builder](./ECommerce.CoreECommerce.Core/Commands/CommandHandler.cs#102) for simplifying the registrations. - Added simple [EventStoreDB extensions](./ECommerce.Core/EventStoreDB/EventStoreDBExtensions.cs) repository to load entity state and store event created by business logic, -- [New, simplified Core infrastructure](./ECommerce.Core/) ## Read Model - Read models are rebuilt with eventual consistency using subscribe to $all stream EventStoreDB feature, @@ -41,10 +40,9 @@ It uses: - Added sample projection for [Shopping cart details](./ECommerce/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs) and slimmed [Shopping cart short info](./ECommerce/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs) as an example of different interpretations of the same events. Shopping cart details also contain a nested collection of product items to show more advanced use case. All event handling is done by functions. It enables easier unit and integration testing. - [Added syntax for self-documenting projection handlers registration](./ECommerce/ShoppingCarts/Configuration.cs#L49). See the details of registration in [EntityFrameworkProjectionBuilder](./ECommerce.Core/Projections/EntityFrameworkProjection.cs#L28). They differentiate case when [a new read model is created](./ECommerce.Core/Projections/EntityFrameworkProjection.cs#L83) from the [update case](./ECommerce.Core/Projections/EntityFrameworkProjection.cs#L108). Update has to support optimistic concurrency. - [example query handlers](./ECommerce/ShoppingCarts/GettingCarts/GetCarts.cs#25) for reading data together with [registration helpers](./ECommerce.Core/Queries/QueryHandler.cs) for EntityFramework querying. -- Added service [EventStoreDBSubscriptionToAll](./ECommerce.Core/Subscriptions/EventStoreDBSubscriptionToAll.cs) to handle subscribing to all. It handles checkpointing and simple retries when the connection is dropped. Added also general [BackgroundWorker](./ECommerce.Api/Core/BackgroundWorker.cs) to wrap the general `IHostedService` handling -- Added [ISubscriptionCheckpointRepository](./ECommerce.Core/Subscriptions/ISubscriptionCheckpointRepository.cs) for handling Subscription checkpointing. -- Added checkpointing to EventStoreDB stream with [EventStoreDBSubscriptionCheckpointRepository](./ECommerce.Core/Subscriptions/EventStoreDBSubscriptionCheckpointRepository.cs), -- Added custom [EventBus](./ECommerce.Core/Events/EventBus.cs) implementation to not take an additional dependency on external frameworks like MediatR. It's not needed as no advanced pipelining is used here. +- Used service [EventStoreDBSubscriptionToAll](../../../Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs) to handle subscribing to all. It handles checkpointing and simple retries when the connection is dropped. Added also general [BackgroundWorker](./ECommerce.Api/Core/BackgroundWorker.cs) to wrap the general `IHostedService` handling +- Used checkpointing to EventStoreDB stream with [EventStoreDBSubscriptionCheckpointRepository](../../../Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionCheckpointRepository.cs), +- Used custom [NoMediatorEventBus](../../../Core/Events/NoMediator/EventBus.cs) implementation to not take an additional dependency on external frameworks like MediatR. It's not needed as no advanced pipelining is used here. ## Tests API integration tests for: diff --git a/Sample/EventStoreDB/Simple/docker/docker-compose.yml b/Sample/EventStoreDB/Simple/docker/docker-compose.yml index 9c6871cff..4af158dfa 100644 --- a/Sample/EventStoreDB/Simple/docker/docker-compose.yml +++ b/Sample/EventStoreDB/Simple/docker/docker-compose.yml @@ -28,26 +28,28 @@ services: # EventStoreDB ####################################################### eventstore.db: - image: eventstore/eventstore:21.2.0-buster-slim + image: eventstore/eventstore:21.10.1-buster-slim + # use this image if you're running ARM-based proc like Apple M1 + # image: ghcr.io/eventstore/eventstore:21.10.0-alpha-arm64v8 environment: - - EVENTSTORE_CLUSTER_SIZE=1 - - EVENTSTORE_RUN_PROJECTIONS=All - - EVENTSTORE_START_STANDARD_PROJECTIONS=true - - EVENTSTORE_EXT_TCP_PORT=1113 - - EVENTSTORE_EXT_HTTP_PORT=2113 - - EVENTSTORE_INSECURE=true - - EVENTSTORE_ENABLE_EXTERNAL_TCP=true - - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true + - EVENTSTORE_CLUSTER_SIZE=1 + - EVENTSTORE_RUN_PROJECTIONS=All + - EVENTSTORE_START_STANDARD_PROJECTIONS=true + - EVENTSTORE_EXT_TCP_PORT=1113 + - EVENTSTORE_HTTP_PORT=2113 + - EVENTSTORE_INSECURE=true + - EVENTSTORE_ENABLE_EXTERNAL_TCP=true + - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true ports: - - '1113:1113' - - '2113:2113' + - '1113:1113' + - '2113:2113' volumes: - - type: volume - source: eventstore-volume-data - target: /var/lib/eventstore - - type: volume - source: eventstore-volume-logs - target: /var/log/eventstore + - type: volume + source: eventstore-volume-data + target: /var/lib/eventstore + - type: volume + source: eventstore-volume-logs + target: /var/log/eventstore networks: - eventstore.db