From f9c9561f40383efda944407646035e7ed7bef9a0 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 9 May 2026 12:54:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(cqrs-benchmarks):=20=E5=AF=B9=E9=BD=90=20re?= =?UTF-8?q?quest=20lifetime=20=E5=AE=BF=E4=B8=BB=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 request lifetime benchmark 的 generated registry,提供最小 generated request descriptor。 - 更新 RequestLifetimeBenchmarks 使用 generated-provider 宿主,并保留 Singleton/Transient 生命周期矩阵控制。 - 补充 dispatcher 缓存清理,避免生命周期矩阵之间互相污染 benchmark 结果。 --- ...neratedRequestLifetimeBenchmarkRegistry.cs | 112 ++++++++++++++++++ .../Messaging/RequestLifetimeBenchmarks.cs | 17 ++- 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs diff --git a/GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs b/GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs new file mode 100644 index 00000000..85192cc7 --- /dev/null +++ b/GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs @@ -0,0 +1,112 @@ +// Copyright (c) 2025-2026 GeWuYou +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using GFramework.Core.Abstractions.Logging; +using GFramework.Cqrs.Abstractions.Cqrs; +using Microsoft.Extensions.DependencyInjection; + +[assembly: GFramework.Cqrs.CqrsHandlerRegistryAttribute( + typeof(GFramework.Cqrs.Benchmarks.Messaging.GeneratedRequestLifetimeBenchmarkRegistry))] + +namespace GFramework.Cqrs.Benchmarks.Messaging; + +/// +/// 为 request 生命周期矩阵 benchmark 提供 hand-written generated registry, +/// 以便在默认 generated-provider 宿主路径上比较不同 handler 生命周期的 dispatch 成本。 +/// +public sealed class GeneratedRequestLifetimeBenchmarkRegistry : + GFramework.Cqrs.ICqrsHandlerRegistry, + GFramework.Cqrs.ICqrsRequestInvokerProvider, + GFramework.Cqrs.IEnumeratesCqrsRequestInvokerDescriptors +{ + private static readonly GFramework.Cqrs.CqrsRequestInvokerDescriptor Descriptor = + new( + typeof(IRequestHandler< + RequestLifetimeBenchmarks.BenchmarkRequest, + RequestLifetimeBenchmarks.BenchmarkResponse>), + typeof(GeneratedRequestLifetimeBenchmarkRegistry).GetMethod( + nameof(InvokeBenchmarkRequestHandler), + BindingFlags.Public | BindingFlags.Static) + ?? throw new InvalidOperationException("Missing generated request lifetime benchmark method.")); + + private static readonly IReadOnlyList Descriptors = + [ + new GFramework.Cqrs.CqrsRequestInvokerDescriptorEntry( + typeof(RequestLifetimeBenchmarks.BenchmarkRequest), + typeof(RequestLifetimeBenchmarks.BenchmarkResponse), + Descriptor) + ]; + + /// + /// 参与程序集注册入口,但不在这里直接写入 handler 生命周期。 + /// + /// 当前 generated registry 拥有的服务集合。 + /// 用于记录 generated registry 注册行为的日志器。 + /// + /// 生命周期矩阵需要让 benchmark 主体显式控制 `Singleton / Transient` 变量。 + /// 因此 registry 只负责暴露 generated descriptor,不在这里抢先注册 handler,避免把默认单例注册混入比较结果。 + /// + public void Register(IServiceCollection services, ILogger logger) + { + ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(logger); + + logger.Debug("Registered generated request lifetime benchmark descriptors."); + } + + /// + /// 返回当前 provider 暴露的全部 generated request invoker 描述符。 + /// + /// 当前 benchmark 需要的 request invoker 描述符集合。 + public IReadOnlyList GetDescriptors() + { + return Descriptors; + } + + /// + /// 为目标请求/响应类型对返回 generated request invoker 描述符。 + /// + /// 待匹配的请求类型。 + /// 待匹配的响应类型。 + /// 命中时返回的 generated descriptor。 + /// 命中当前 benchmark 的请求/响应类型对时返回 + public bool TryGetDescriptor( + Type requestType, + Type responseType, + out GFramework.Cqrs.CqrsRequestInvokerDescriptor? descriptor) + { + if (requestType == typeof(RequestLifetimeBenchmarks.BenchmarkRequest) && + responseType == typeof(RequestLifetimeBenchmarks.BenchmarkResponse)) + { + descriptor = Descriptor; + return true; + } + + descriptor = null; + return false; + } + + /// + /// 模拟 generated request invoker provider 为生命周期矩阵 benchmark 产出的开放静态调用入口。 + /// + /// 当前请求对应的 handler 实例。 + /// 待分发的 request。 + /// 调用方传入的取消令牌。 + /// 交给目标 request handler 处理后的响应任务。 + public static ValueTask InvokeBenchmarkRequestHandler( + object handler, + object request, + CancellationToken cancellationToken) + { + var typedHandler = (IRequestHandler< + RequestLifetimeBenchmarks.BenchmarkRequest, + RequestLifetimeBenchmarks.BenchmarkResponse>)handler; + var typedRequest = (RequestLifetimeBenchmarks.BenchmarkRequest)request; + return typedHandler.Handle(typedRequest, cancellationToken); + } +} diff --git a/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs b/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs index 735705db..2e342dd6 100644 --- a/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs +++ b/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs @@ -85,14 +85,18 @@ public class RequestLifetimeBenchmarks MinLevel = LogLevel.Fatal }; Fixture.Setup($"RequestLifetime/{Lifetime}", handlerCount: 1, pipelineCount: 0); + BenchmarkDispatcherCacheHelper.ClearDispatcherCaches(); _baselineHandler = new BenchmarkRequestHandler(); _request = new BenchmarkRequest(Guid.NewGuid()); _container = BenchmarkHostFactory.CreateFrozenGFrameworkContainer(container => { + BenchmarkHostFactory.RegisterGeneratedBenchmarkRegistry(container); RegisterGFrameworkHandler(container, Lifetime); }); + // 容器内已提前保留默认 runtime 以支撑 generated registry 接线; + // 这里额外创建带生命周期后缀的 runtime,只是为了区分不同 benchmark 矩阵的 dispatcher 日志。 _runtime = GFramework.Cqrs.CqrsRuntimeFactory.CreateRuntime( _container, LoggerFactoryResolver.Provider.CreateLogger(nameof(RequestLifetimeBenchmarks) + "." + Lifetime)); @@ -111,7 +115,14 @@ public class RequestLifetimeBenchmarks [GlobalCleanup] public void Cleanup() { - BenchmarkCleanupHelper.DisposeAll(_container, _serviceProvider); + try + { + BenchmarkCleanupHelper.DisposeAll(_container, _serviceProvider); + } + finally + { + BenchmarkDispatcherCacheHelper.ClearDispatcherCaches(); + } } /// @@ -146,6 +157,10 @@ public class RequestLifetimeBenchmarks /// /// 当前 benchmark 拥有并负责释放的容器。 /// 待比较的 handler 生命周期。 + /// + /// 先通过 generated registry 提供静态 descriptor,再显式覆盖 handler 生命周期, + /// 可以把比较变量收敛到 handler 解析成本,而不是 descriptor 发现路径本身。 + /// private static void RegisterGFrameworkHandler(MicrosoftDiContainer container, HandlerLifetime lifetime) { ArgumentNullException.ThrowIfNull(container);