diff --git a/src/Benchmark/Bench.cs b/src/Benchmark/Bench.cs new file mode 100644 index 0000000..39ef892 --- /dev/null +++ b/src/Benchmark/Bench.cs @@ -0,0 +1,76 @@ +using BenchmarkDotNet.Attributes; +using Fluss; +using Fluss.Authentication; +using Fluss.Events; +using Fluss.ReadModel; +using Microsoft.Extensions.DependencyInjection; + +namespace Benchmark; + +[SimpleJob] +[MemoryDiagnoser] +public class Bench +{ + [IterationSetup] + public void Setup() + { + var sc = new ServiceCollection(); + sc.AddEventSourcing(); + sc.AddPoliciesFrom(typeof(Bench).Assembly); + + _sp = sc.BuildServiceProvider(); + } + + ServiceProvider _sp = null!; + + [Benchmark] + public async Task PublishEventsAndRead() + { + var sum = 0; + for (var j = 0; j < 1000; j++) + { + await _sp.GetSystemUserUnitOfWorkFactory().Commit(async unitOfWork => { + for (var i = 0; i < 50; i++) + { + await unitOfWork.Publish(new TestEvent(1)); + await unitOfWork.Publish(new TestEvent(2)); + } + }); + + var unitOfWork = _sp.GetSystemUserUnitOfWork(); + var readModel1 = await unitOfWork.GetReadModel(1); + var readModel2 = await unitOfWork.GetReadModel(2); + sum += readModel1.GotEvents + readModel2.GotEvents; + } + + return sum; + } +} + +public class AllowAllPolicy : Policy { + public ValueTask AuthenticateEvent(EventEnvelope envelope, IAuthContext authContext) + { + return ValueTask.FromResult(true); + } + + public ValueTask AuthenticateReadModel(IReadModel readModel, IAuthContext authContext) + { + return ValueTask.FromResult(true); + } +} + +public record TestEvent(int Id) : Event; + +public record TestReadModel : ReadModelWithKey +{ + public int GotEvents { get; private init; } + + protected override TestReadModel When(EventEnvelope envelope) + { + return envelope.Event switch + { + TestEvent testEvent when testEvent.Id == Id => this with { GotEvents = GotEvents + 1 }, + _ => this, + }; + } +} diff --git a/src/Benchmark/Benchmark.csproj b/src/Benchmark/Benchmark.csproj new file mode 100644 index 0000000..a884b6e --- /dev/null +++ b/src/Benchmark/Benchmark.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Benchmark/Program.cs b/src/Benchmark/Program.cs new file mode 100644 index 0000000..d7bd483 --- /dev/null +++ b/src/Benchmark/Program.cs @@ -0,0 +1,4 @@ +using Benchmark; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); \ No newline at end of file diff --git a/src/Fluss.sln b/src/Fluss.sln index 1154d39..0ae3d82 100644 --- a/src/Fluss.sln +++ b/src/Fluss.sln @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluss.Testing", "Fluss.Test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluss.Regen", "Fluss.Regen\Fluss.Regen.csproj", "{6E250321-6993-4B94-8600-85E15BF713FA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "Benchmark\Benchmark.csproj", "{970AB461-4D44-4B99-AACA-7DAA569D4C34}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -42,5 +44,9 @@ Global {6E250321-6993-4B94-8600-85E15BF713FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6E250321-6993-4B94-8600-85E15BF713FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6E250321-6993-4B94-8600-85E15BF713FA}.Release|Any CPU.Build.0 = Release|Any CPU + {970AB461-4D44-4B99-AACA-7DAA569D4C34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {970AB461-4D44-4B99-AACA-7DAA569D4C34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {970AB461-4D44-4B99-AACA-7DAA569D4C34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {970AB461-4D44-4B99-AACA-7DAA569D4C34}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/Fluss/UnitOfWork/UnitOfWork.Authorization.cs b/src/Fluss/UnitOfWork/UnitOfWork.Authorization.cs index fc0672a..c0e027c 100644 --- a/src/Fluss/UnitOfWork/UnitOfWork.Authorization.cs +++ b/src/Fluss/UnitOfWork/UnitOfWork.Authorization.cs @@ -1,9 +1,6 @@ using Fluss.Authentication; using Fluss.Events; using Fluss.ReadModel; -#if !DEBUG -using Fluss.Extensions; -#endif namespace Fluss; @@ -21,7 +18,7 @@ private async ValueTask AuthorizeUsage(EventEnvelope envelope) return accepted.Count > 0; #else - return await _policies.Select(p => p.AuthenticateEvent(envelope, ac)).AnyAsync(); + return await AnyAsync(_policies.Select(p => p.AuthenticateEvent(envelope, ac))); #endif } @@ -37,7 +34,19 @@ private async ValueTask AuthorizeUsage(IReadModel eventListener) return accepted.Count > 0; #else - return await _policies.Select(p => p.AuthenticateReadModel(eventListener, ac)).AnyAsync(); + return await AnyAsync(_policies.Select(p => p.AuthenticateReadModel(eventListener, ac))); #endif } + + private static async ValueTask AnyAsync(IEnumerable> valueTasks) + { + foreach (var valueTask in valueTasks) + { + if (await valueTask) + { + return true; + } + } + return false; + } }