diff --git a/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Backend/Program.cs b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Backend/Program.cs index aaf63b9..1d2a8cd 100644 --- a/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Backend/Program.cs +++ b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Backend/Program.cs @@ -3,12 +3,16 @@ using Akka.Persistence.SqlServer.Hosting; using CqrsSqlServer.Backend.Actors; using CqrsSqlServer.DataModel; +using CqrsSqlServer.Shared; using CqrsSqlServer.Shared.Serialization; using CqrsSqlServer.Shared.Sharding; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Petabridge.Cmd.Cluster; +using Petabridge.Cmd.Cluster.Sharding; +using Petabridge.Cmd.Host; var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; @@ -44,8 +48,16 @@ Props.Create(() => new GenericChildPerEntityParent(new ProductMessageRouter(), ProductTotalsActor.GetProps)), "productTotals"); - registry.Register(parentActor); - }); + registry.Register(parentActor); + }) + .AddPetabridgeCmd(cmd => + { + + }) + .AddStartup((system, registry) => + { + new FakeDataGenerator().Generate(system, registry, 100); + });; }); }); diff --git a/src/cqrs/cqrs-sqlserver/CqrsSqlServer.DataModel/CqrsSqlServer.DataModel.csproj b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.DataModel/CqrsSqlServer.DataModel.csproj index de34e12..4d0a1e4 100644 --- a/src/cqrs/cqrs-sqlserver/CqrsSqlServer.DataModel/CqrsSqlServer.DataModel.csproj +++ b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.DataModel/CqrsSqlServer.DataModel.csproj @@ -17,7 +17,6 @@ - PreserveNewest diff --git a/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Shared/CqrsSqlServer.Shared.csproj b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Shared/CqrsSqlServer.Shared.csproj index 8b7a50c..9a7f29c 100644 --- a/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Shared/CqrsSqlServer.Shared.csproj +++ b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Shared/CqrsSqlServer.Shared.csproj @@ -9,6 +9,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Shared/FakeDataGenerator.cs b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Shared/FakeDataGenerator.cs new file mode 100644 index 0000000..4f4bc67 --- /dev/null +++ b/src/cqrs/cqrs-sqlserver/CqrsSqlServer.Shared/FakeDataGenerator.cs @@ -0,0 +1,91 @@ +using Akka.Actor; +using Akka.Event; +using Akka.Hosting; +using Bogus; +using CqrsSqlServer.Shared.Commands; +using CqrsSqlServer.Shared.Sharding; + +namespace CqrsSqlServer.Shared; + +public class FakeDataGenerator +{ + private readonly Faker _productGenerator; + + public FakeDataGenerator() + { + Randomizer.Seed = new Random(123456); + _productGenerator = new Faker() + .CustomInstantiator(f => + { + var count = f.Random.Int(0, 3); + return new CreateProduct( + f.Random.Guid().ToString(), + f.Commerce.ProductName(), + f.Finance.Amount(min: 1, max: 1000), + f.Random.Int(1, 1000), + count == 0 ? Array.Empty() : f.Commerce.Categories(count) + ); + }); + } + + public void Generate(ActorSystem system, IActorRegistry registry, int count) + { + var log = Logging.GetLogger(system, nameof(FakeDataGenerator)); + var shardRegion = registry.Get(); + + GenerateAsync(count, shardRegion, log) + .ContinueWith(t => + { + if (!t.IsCompletedSuccessfully) + { + log.Error(t.Exception, "Failed to generate fake data"); + } + }) + .ConfigureAwait(false); + } + + private async Task GenerateAsync(int count, IActorRef shardRegion, ILoggingAdapter log) + { + log.Info($"Generating {count} fake data"); + var items = new List(); + var total = 0; + foreach (var _ in Enumerable.Range(0, count)) + { + var item = _productGenerator.Generate(); + items.Add(item); + var response = await shardRegion.Ask(item, TimeSpan.FromSeconds(3)); + if (!response.Success) + { + log.Error(response.Message); + } + else + { + total++; + } + } + + var purchaseCount = count * 5; + var rnd = Randomizer.Seed; + var purchaseTotal = 0; + var twoMinutes = TimeSpan.FromMinutes(2); + var rollBackMinutes = twoMinutes * (purchaseCount + 1); + var now = DateTime.UtcNow - rollBackMinutes; + foreach (var _ in Enumerable.Range(0, purchaseCount)) + { + var item = items[rnd.Next(0, items.Count)]; + var newOrder = new ProductOrder(Guid.NewGuid().ToString(), item.ProductId, rnd.Next(1, 100), now); + now += twoMinutes; + var createOrderCommand = new PurchaseProduct(newOrder); + var response = await shardRegion.Ask(createOrderCommand, TimeSpan.FromSeconds(3)); + if (!response.Success) + { + log.Error(response.Message); + } + else + { + purchaseTotal++; + } + } + log.Info($"Generated {total} fake data and {purchaseTotal} fake purchases"); + } +} \ No newline at end of file