Skip to content

Commit

Permalink
Updated EventStoreDB samples documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed Mar 3, 2022
1 parent 4a6e991 commit 1134aa8
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 52 deletions.
Expand Up @@ -51,8 +51,9 @@ ILogger<EventStoreDBSubscriptionToAll> 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;

Expand Down
10 changes: 10 additions & 0 deletions Sample/EventStoreDB/ECommerce/ECommerce.sln
Expand Up @@ -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
Expand Down
17 changes: 8 additions & 9 deletions Sample/EventStoreDB/ECommerce/README.md
Expand Up @@ -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):
Expand All @@ -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
Expand Down
40 changes: 20 additions & 20 deletions Sample/EventStoreDB/ECommerce/docker/docker-compose.yml
Expand Up @@ -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:
Expand Down
12 changes: 12 additions & 0 deletions Sample/EventStoreDB/Simple/ECommerce.sln
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
8 changes: 3 additions & 5 deletions Sample/EventStoreDB/Simple/README.md
Expand Up @@ -33,18 +33,16 @@ 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,
- Used Entity Framework to store projection data into Postgres tables,
- 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:
Expand Down
36 changes: 19 additions & 17 deletions Sample/EventStoreDB/Simple/docker/docker-compose.yml
Expand Up @@ -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

Expand Down

0 comments on commit 1134aa8

Please sign in to comment.