-
Notifications
You must be signed in to change notification settings - Fork 264
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into bash-scripts
- Loading branch information
Showing
3 changed files
with
96 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# Akka.NET Event-Sourcing and CQRS with Akka.Persistence | ||
|
||
The goal of this sample is to demonstrate: | ||
|
||
1. How do to basic event-sourcing with Akka.Persistence; | ||
2. How to use Akka.Persistence.Query to project events written to Akka.Persistence; and | ||
3. How to use Entity Framework Core to create CQRS-style read models that are used by the frontend application. | ||
|
||
## Technology | ||
|
||
This solution is built with: | ||
|
||
- Minimal APIs; | ||
- C# `record` types; | ||
- [Blazor](https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor) and [MudBlazor](https://www.mudblazor.com/); | ||
- Google.Protobuf for message and state schema; | ||
- Akka.NET v1.5 w/ Akka.Persistence and [Akka.Persistence.Query](https://getakka.net/articles/persistence/persistence-query.html); | ||
- [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/), for our read models; | ||
- [Akka.Persistence.Sql](https://github.com/akkadotnet/Akka.Persistence.Sql); and | ||
- [Akka.Hosting](https://github.com/akkadotnet/Akka.Hosting) - which minimizes the amount of configuration for Akka.NET to practically zero. | ||
|
||
## Domain | ||
|
||
Like all of the samples in this repository, we are using a simple domain since the focus of the sample is meant to be _how to use Akka.NET infrastructure succinctly and successfully_. That being said, it's still worth understanding what our domain does: product inventory + revenue tracking. It's the same domain as ["Akka.NET Cluster.Sharding with Akka.Persistence.SqlServer and Razor Pages"](../../clustering/sharding-sqlserver). | ||
|
||
> This app does not use Akka.Cluster, although it could be easily modified to do so (nothing would really change other than migrating some actors to `ShardRegion`s and `SingletonManager`s). | ||
In the `CqrsSqlServer.Backend` application: | ||
|
||
1. **`ProductTotalsActor`** - our `ReceivePersistentActor` that will process `IProductCommand `, transforming them into (0..N) `IProductEvent`s, updating its `ProductState`, and replying to the original sender with a `ProductCommandResponse` with the results of each command. This entity actor demonstrates one of the more robust ways of executing event-sourcing on top of Akka.Persistence using C#9 `record` types and cleanly separating command / event / query message types from each other. | ||
2. **`ProductProjectorActor`** - a singleton `ReceivePersistentActor` that functions as a projector + materialized view creator for all of the events saved by _all_ of the `ProductTotalsActor` instance. It uses Akka.Persistence.Query's `EventsByTag` functionality to query all of the events tagged by the `MessageTagger` - and then safely renders read models using the `CqrsSqlServerContext` EF Core model. | ||
|
||
In the `CqrsSqlServer.Frontend` application, we don't use Akka.NET _at all_ - we just spin up a simple Blazor UI that reads data that reads the `CqrsSqlServerContext` read models. | ||
|
||
## Running This Sample | ||
|
||
### Launch Dependencies | ||
|
||
To run this sample, we first need to spin up our dependencies - a SQL Server instance with a predefined `Akka` database ready to be configured. | ||
|
||
**Windows** | ||
|
||
```shell | ||
start-dependencies.cmd | ||
``` | ||
|
||
**Linux or OS X** | ||
|
||
```shell | ||
./start-dependencies.sh | ||
``` | ||
|
||
This will build a copy of our [MSSQL image](https://github.com/petabridge/akkadotnet-code-samples/tree/master/infrastructure/mssql) and run it on port 1533. The sample is already pre-configured to connect to it at startup. | ||
|
||
### `dotnet ef` Dependency | ||
|
||
`start-dependencies.cmd` and `start-dependencies.sh` will also run `dotnet ef database update` - make sure you have the Entity Framework Core `dotnet` CLI installed! | ||
|
||
```shell | ||
dotnet tool install --global dotnet-ef | ||
``` | ||
|
||
or update to the latest | ||
|
||
```shell | ||
dotnet tool update --global dotnet-ef | ||
``` | ||
### Run the Sample | ||
|
||
First, take a look at the `appSettings.json` for `CqrsSqlServer.Backend.csproj`: | ||
|
||
```json | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Debug", | ||
"System": "Information", | ||
"Microsoft": "Information" | ||
} | ||
}, | ||
"SeedDb": true | ||
} | ||
``` | ||
|
||
Make sure you run with `"SeedDb": true` the first time you launch the application, otherwise it won't do anything. | ||
|
||
If you run the application a second time with this setting, some of the random data generated by Bogus might conflict with data already stored inside the application - that should be fine. Those events will just get ignored by the persistent actors. | ||
|
||
Launch `CqrsSqlServer.Backend.csproj` via Visual Studio, Rider, or the `dotnet` CLI first. | ||
|
||
Then, once that app is running, launch `CqrsSqlServer.Frontend.csproj` and go to http://localhost:5191/ |