Skip to content

Feat/Enhance CQRS benchmarks coverage and generated invoker descriptor validation#348

Merged
GeWuYou merged 10 commits into
mainfrom
feat/cqrs-optimization
May 11, 2026
Merged

Feat/Enhance CQRS benchmarks coverage and generated invoker descriptor validation#348
GeWuYou merged 10 commits into
mainfrom
feat/cqrs-optimization

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented May 11, 2026

Summary by CodeRabbit

版本更新说明

  • 性能评测

    • 新增多套基准:通知生命周期、通知冷启动、请求冷启动、流冷启动与流启动对比
  • 可靠性改进

    • 增强生成器元数据预校验与去重逻辑,枚举异常时回退反射路径
    • 通知发布策略更严格:默认仅接受单一发布者并补充冲突检测
  • 测试

    • 扩展大量单元/集成测试,覆盖 dispatcher 缓存、生成描述符边界与通知发布缓存语义
  • 文档澄清

    • 明确生成器覆盖范围(仅 request/stream)、以及与旧 Command/Query 的兼容桥接与运行时约束

Review Change Stack

GeWuYou added 9 commits May 11, 2026 12:37
- 更新 CQRS 栏目中的 generated invoker、fallback 分层与 notification publisher 选择边界说明

- 对齐生成器专题页与当前 runtime 注册和分发实现的实际行为
- 新增 notification publisher 多实例冲突时抛错的回归测试

- 补充首次解析后复用同一 publisher 且不重复查容器的缓存测试

- 更新测试发布器计数以验证缓存命中的发布调用次数
- 新增 RequestStartupBenchmarks 的 Mediator 初始化与冷启动 benchmark 路径

- 更新 request 与 handler 契约以复用单文件内的 Mediator concrete host 对照
- 修复 generated request/stream invoker descriptor 枚举阶段对异常、重复 pair 与不一致元数据的防守行为

- 补充 generated invoker provider descriptor 边界回归测试,锁定回退与首条生效语义
- 更新 archive todo 顶部导航,补充截止恢复点、阶段索引与跳转约定

- 更新 archive trace 顶部索引,突出验证锚点与阶段回看入口
- 更新当前 HEAD 已覆盖的 request、stream、notification benchmark 矩阵

- 补充 --artifacts-suffix 的并发运行隔离约束与使用边界

- 明确 short-job smoke 的结论边界,并将未覆盖维度改写为当前缺口
- 新增 StreamStartupBenchmarks,补齐 stream 的 initialization 与 cold-start first-hit 对照
- 内嵌 generated registry 与最小宿主搭建,保持 benchmark 场景在单文件内自管理
- 新增 NotificationStartupBenchmarks,补齐 notification 的 Initialization 与 ColdStart 对称矩阵

- 复用最小宿主搭建路径,对齐 GFramework.CQRS、Mediator 与 MediatR 的单处理器首击发布对照

- 修复 cold-start 方法的资源释放时序,确保 benchmark 构建零警告通过
- 新增 NotificationLifetime 基准并补充验证结果

- 更新 CQRS README 与 legacy Command/Query 迁移说明

- 补充 registration fallback 回归测试并同步 ai-plan 恢复点
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6571d5ec-9b4e-439d-b1c8-3f7ce9f5bb8d

📥 Commits

Reviewing files that changed from the base of the PR and between babd132 and 4e98b63.

📒 Files selected for processing (5)
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
✅ Files skipped from review due to trivial changes (1)
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs
📜 Recent review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (C#)
🧰 Additional context used
📓 Path-based instructions (6)
**/Cqrs/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Use CQRS (Command Query Responsibility Segregation) pattern with the Cqrs naming entry point instead of the historical Mediator alias

Files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Apply [Log] attribute for automatic logging field and logging helper method generation
Apply [Priority] attribute for automatic priority comparison implementation generation
Apply [GenerateEnumExtensions] attribute to generate enumeration extension capabilities
Apply [ContextAware] attribute to automatically implement IContextAware boilerplate logic

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///)
XML documentation comments MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable, explaining intent, contract, and usage constraints instead of restating syntax
If a member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly in XML documentation
Add inline comments for non-trivial logic, concurrency or threading behavior, performance-sensitive paths, workarounds and compatibility constraints, edge cases, registration order, lifecycle sequencing, and generated code assumptions
Avoid obvious comments such as // increment i
Methods with non-trivial logic MUST document: The core idea, Key decisions, and Edge case handling, if any
Comments MUST NOT be trivial, redundant, or misleading. Prefer explaining why and when, not just what. Code should remain understandable without requiring external context. Prefer slightly more explanation over too little for framework code
Do not rely on implicit imports. Declare every required using explicitly
Write null-safe code that respects nullable annotations instead of suppressing warnings by default
Use the namespace pattern GFramework.{Module}.{Feature} with PascalCase segments
Follow standard C# naming: Types, methods, properties, events, and constants use PascalCase; Interfaces use I prefix; Parameters and locals use camelCase; Private fields use _camelCase
Use 4 spaces for indentation. Do not use tabs
Use Allman braces
Keep using directives at the top...

Files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
**/*.Tests/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.Tests/**/*.cs: Mirror the source structure in test projects whenever practical
Reuse existing architecture test infrastructure when relevant: ArchitectureTestsBase<T>, SyncTestArchitecture, AsyncTestArchitecture

Files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
ai-plan/public/**

📄 CodeRabbit inference engine (AGENTS.md)

ai-plan/public/**: Contributors MUST keep committed ai-plan/public/** content safe to publish in Git history
Active tracking and trace files are recovery entrypoints, not append-only changelogs. They MUST stay concise enough for boot to locate the current recovery point quickly
When completed and validated stages begin to accumulate, contributors MUST archive their detailed history out of the active todos/ and traces/ entry files in the same change. Keep only the current recovery point, active facts, active risks, immediate next step, and pointers to the relevant archive files in the default boot path
When a topic is fully complete, move the entire topic directory under ai-plan/public/archive/<topic>/ and remove it from ai-plan/public/README.md in the same change
When a task spans multiple commits or is likely to exceed a single agent context window, update both the recovery document and the trace at each meaningful milestone before pausing or handing work off
If subagents are used on a complex task, the main agent MUST capture the delegated scope and any accepted findings in the active recovery document or trace before continuing implementation

Files:

  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
ai-plan/**

📄 CodeRabbit inference engine (AGENTS.md)

ai-plan/**: Never write secrets, tokens, credentials, private keys, machine usernames, home-directory paths, hostnames, IP addresses, proprietary URLs, or other sensitive environment details into any ai-plan/** file
Never record absolute file-system paths in ai-plan/**; use repository-relative paths, branch names, PR numbers, or stable document identifiers instead

Files:

  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
ai-plan/public/**/traces/**

📄 CodeRabbit inference engine (AGENTS.md)

Contributors MUST maintain a matching execution trace under ai-plan/public/<topic>/traces/ for complex work. The trace should record the current date, key decisions, validation milestones, and the immediate next step

Files:

  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
🧠 Learnings (2)
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
📚 Learning: 2026-05-11T06:15:15.057Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 348
File: GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs:52-68
Timestamp: 2026-05-11T06:15:15.057Z
Learning: In the GeWuYou/GFramework repo, do not treat a missing [GenerateEnumExtensions] attribute as a code review issue for every enum. Skip the check for:
1) local/private benchmark enums (e.g., enums defined for benchmarks such as HandlerLifetime in GFramework.Cqrs.Benchmarks),
2) enums located in projects that do NOT reference the source-generator abstractions package (the generator won’t apply there), and
3) core framework/runtime-style code paths that AGENTS.md explicitly restricts from using generator-attribute usage.
If an enum falls into any of these cases, do not flag the missing [GenerateEnumExtensions] (it has been triaged as a generalized false positive for these scenarios).

Applied to files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
🪛 LanguageTool
ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md

[grammar] ~10-~10: Ensure spelling is correct
Context: ... 2026-05-11 ### 阶段:PR #348 latest-head review 再收口(CQRS-REWRITE-RP-134) - 重新执行 `$gframework-pr...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (6)
ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md (2)

10-32: 追踪记录清晰完整!

本段准确记录了 PR #348 review 结论与实施范围,包括接受的修复项(descriptor 预热逻辑、invoker 相等性判断放宽、XML 契约补全)以及回归测试覆盖,与代码变更保持一致,有助于快速恢复上下文。


91-141: Batch 收口记录完整,验证结果清晰!

本段详细记录了 batch 工作范围、验证步骤与 benchmark 结果摘要,明确了停止边界(reviewability/context-budget),便于后续 PR review 时快速了解本轮变更的覆盖面与性能基线。

GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs (4)

451-569: Request 路径边界测试覆盖完整!

新增的 4 个 request descriptor 测试全面覆盖了枚举异常、重复条目、枚举与 provider 不一致、以及"首个无效后续有效"等关键边界场景,确保 registrar 的 descriptor 预热逻辑具备正确的防御性与回退能力。测试结构清晰,断言准确。


476-609: Stream 路径边界测试覆盖完整!

新增的 4 个 stream descriptor 测试与 request 路径对称,全面覆盖了枚举异常、重复条目、枚举与 provider 不一致、以及"首个无效后续有效"等关键场景,确保 stream invoker provider 的 descriptor 预热逻辑具备相同的防御性与回退能力。异步流处理正确,断言准确。


1023-1123: 枚举异常场景 mock 实现准确!

ThrowingEnumeratingRequestInvokerProviderRegistryThrowingEnumeratingStreamInvokerProviderRegistry 准确模拟了 descriptor 枚举阶段抛出异常的场景,同时保持 TryGetDescriptor() 可用,有效验证了 registrar 在枚举失败时的隔离性与回退逻辑。


1128-1544: 边界场景 mock 实现清晰且全面!

新增的 6 个 mock registry 类准确模拟了重复条目、枚举与 provider 不一致、以及"首个无效后续有效"等复杂边界场景。特别是 InvalidThenValidDuplicate* 系列通过返回 [InvalidDescriptor, ValidDescriptor] 有效验证了 registrar 不会因首个同键 descriptor 无效而过早去重,确保后续有效 descriptor 仍能被接受,符合 trace 文档中记录的修复逻辑。


📝 Walkthrough

Walkthrough

本 PR 增加多个 BenchmarkDotNet 套件(通知生命周期/启动、请求/流 启动)、扩展单元测试覆盖以验证 dispatcher 缓存与生成描述符边界、在 CqrsHandlerRegistrar 中加入生成描述符的防御与验证逻辑,并同步更新 CQRS 文档与迁移追踪记录。

Changes

基准测试基础设施与实现

Layer / File(s) Summary
通知生命周期基准
GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs
新增 NotificationLifetimeBenchmarks,按 Singleton/Scoped/Transient 比较直接调用、GFramework.PublishAsync 与 MediatR.Publish 三条路径(Scoped 每次 publish 建立显式 scope)。
通知启动冷启动基准
GFramework.Cqrs.Benchmarks/Messaging/NotificationStartupBenchmarks.cs
新增 NotificationStartupBenchmarks,测量 GFramework.CQRS、MediatR 与 GeneratedMediator 的初始化与首次 publish 冷启动成本;GlobalSetup 构建共享主机,IterationSetup 清空 dispatcher 缓存。
请求基准中的 Mediator 支持
GFramework.Cqrs.Benchmarks/Messaging/RequestStartupBenchmarks.cs
为 RequestStartupBenchmarks 增加 NuGet GeneratedMediator 路径,添加 Initialization_Mediator 与 ColdStart_Mediator 基准,并扩展 BenchmarkRequest/Handler 实现 Mediator 接口。
流启动基准与生成注册表
GFramework.Cqrs.Benchmarks/Messaging/StreamStartupBenchmarks.cs
新增 StreamStartupBenchmarks,测量流处理冷启动与首元素消费,包含 MediatR、GFramework 反射与生成运行时对比,并加入手写 GeneratedRegistry 提供描述符与调用入口。
基准覆盖范围文档
GFramework.Cqrs.Benchmarks/README.md
将 README 重写为 request/stream/notification × steady-state/startup 覆盖矩阵,新增并发运行约束、结果解读边界与当前覆盖缺口说明。

单元测试与验证覆盖

Layer / File(s) Summary
分发器缓存行为测试
GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs
新增四个测试验证零行为场景不会提前创建管道执行者,共享绑定在后续有行为时会创建执行者并支持上下文重注入;引入 DispatcherCacheFixtureOptions 以按需构建隔离 frozen 容器。
生成调用器描述符验证测试
GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
新增多项测试覆盖 provider.GetDescriptors() 抛出时回退反射、枚举重复条目时优先使用首个有效描述符、枚举条目与 TryGetDescriptor 不匹配时忽略并回退运行时、以及首个重复条目无效时使用后续有效项;新增若干 mock registry 以触发这些情形。
通知发布者单例性与缓存测试
GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
新增测试断言当注册多个 INotificationPublisher 时抛出 InvalidOperationException,并新增测试验证 dispatcher 在首次解析后缓存该发布者(TrackingNotificationPublisher 增加 PublishCallCount)。
程序集名称回退机制测试
GFramework.Cqrs.Tests/Cqrs/CqrsRegistrationServiceTests.cs
新增测试验证当 Assembly.FullName 缺失时回退到 AssemblyName.Name,若两者均缺失则回退到 Assembly.ToString() 作为稳定键并实现去重;扩展 CreateAssembly helper 支持可配置降级路径。

运行时实现与文档

Layer / File(s) Summary
描述符枚举防御与验证
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
在 RegisterGeneratedRequestInvokerDescriptors 与 RegisterGeneratedStreamInvokerDescriptors 中加入 try/catch、null 列表/条目处理、基于 InvokerDescriptorKey 的去重,并在注册前使用 TryValidateEnumeratedRequestInvokerDescriptor/TryValidateEnumeratedStreamInvokerDescriptor 验证枚举条目与 provider.TryGetDescriptor 返回值相符。
CQRS 运行时与生成器文档
GFramework.Cqrs/README.mddocs/zh-CN/core/cqrs.mddocs/zh-CN/source-generators/cqrs-handler-registry-generator.md
文档澄清 generated invoker 仅覆盖 request 与 stream,notification 发布不走生成通道;默认 runtime 仅消费单个 INotificationPublisher 且重复注册报错;补充 TaskWhenAllNotificationPublisher 的语义与 CqrsReflectionFallbackAttribute 的优先级/回退行为。
遗留命令与查询 bridge 文档
docs/zh-CN/core/command.mddocs/zh-CN/core/query.md
说明 legacy SendCommand/SendQuery 在标准架构下如何包装为 bridge request 并交由 ICqrsRuntime 以复用 CQRS pipeline,以及直接实例化 executor 时的回退行为与迁移指引。

迁移追踪与治理

Layer / File(s) Summary
迁移追踪与恢复点更新
ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
更新恢复点与 PR 锚点(RP-134 / PR #348),记录本轮 Phase 的结论、已补齐/未补齐项、基准 smoke ColdStart 指标及下一步建议顺序。
归档导航与索引
ai-plan/public/cqrs-rewrite/archive/...
添加归档使用说明、归档截止点、阶段索引与跳转约定,并在迁移 trace 文档顶部加入快速导航头。
阶段执行记录
ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
新增 RP-133 / RP-134 阶段条目,记录批次收口策略、已接受范围、验证命令与基准结果摘要。

🎯 4 (Complex) | ⏱️ ~45 minutes

可能相关的 PR

  • GeWuYou/GFramework#347: 与本 PR 的基准基础设施(作用域容器、scoped-publish 路径)直接相关。
  • GeWuYou/GFramework#261: 与本 PR 在 CqrsHandlerRegistrar 的生成描述符消费/去重/激活逻辑上存在代码级关联。
  • GeWuYou/GFramework#340: 两者均添加对 GeneratedMediator 的基准路径并修改相关 DI/分发器快速路径,存在重叠关注点。
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 标题准确概括了主要变更:增强 CQRS benchmark 覆盖范围和改进 generated invoker descriptor 验证,与文件变更内容高度匹配。
Docstring Coverage ✅ Passed Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cqrs-optimization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2367    ↑24 2367    ↑24 0 0 0 0 37.1s    ↑371ms

Test Results

passed 2367 passed ↑24

Details

tests 2367 tests ↑24
clock 37.1s ↑371ms
tool nunit
build CI - Build & Test arrow-right build-and-test link #1107
pull-request Feat/cqrs optimization link #348

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2254 0 3 4.8s

Fail Rate

Fail Rate 0.00%
Test 📝 Results 📊 Passed ✅ Failed ❌ Fail Rate (%) 📈
CreateStream_Should_Throw_When_Stream_Pipeline_Behavior_Context_Does_Not_Implement_IArchitectureContext 16 15 1 6.25    ↓0.42
PublishAsync_Should_Stop_After_First_Handler_Exception_When_Using_Default_Publisher 34 33 1 2.94    ↓0.09
PublishAsync_Should_Throw_When_Context_Does_Not_Implement_IArchitectureContext 38 37 1 2.63    ↓0.07

build-and-test: Run #1107

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2367 2367 0 0 0 0 0 37.1s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 34 4.1s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 49 1.3s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 49 2.1s 2.3s
Generates_Scene_Behavior_Boilerplate 49 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 49 1.1s 1.1s
Append_ShouldNotBlock 49 1.0s 1.0s
Context_Caching_Should_Improve_Performance 49 782ms 794ms
PendingCount_ShouldReflectQueuedEntries 49 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 49 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 49 401ms 402ms

± Comparison with run #1106 at 1d63a95 | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 49 runs.

Github Test Reporter by CTRF 💚

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 11, 2026

⚠️MegaLinter analysis: Success with warnings

Descriptor Linter Files Fixed Errors Warnings Elapsed time
⚠️ CSHARP dotnet-format yes 1 no 5.21s
✅ REPOSITORY gitleaks yes no no 8.12s
✅ REPOSITORY trufflehog yes no no 5.94s

Detailed Issues

⚠️ CSHARP / dotnet-format - 1 error
Welcome to .NET 9.0!
---------------------
SDK Version: 9.0.114

----------------
Installed an ASP.NET Core HTTPS development certificate.
To trust the certificate, run 'dotnet dev-certs https --trust'
Learn about HTTPS: https://aka.ms/dotnet-https

----------------
Write your first app: https://aka.ms/dotnet-hello-world
Find out what's new: https://aka.ms/dotnet-whats-new
Explore documentation: https://aka.ms/dotnet-docs
Report issues and find source on GitHub: https://github.com/dotnet/core
Use 'dotnet --help' to see available commands or visit: https://aka.ms/dotnet-cli
--------------------------------------------------------------------------------------
Unhandled exception: System.Exception: Restore operation failed.
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.OpenMSBuildWorkspaceAsync(String solutionOrProjectPath, WorkspaceType workspaceType, Boolean noRestore, Boolean requiresSemantics, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.FormatWorkspaceAsync(FormatOptions formatOptions, ILogger logger, CancellationToken cancellationToken, String binaryLogPath)
   at Microsoft.CodeAnalysis.Tools.FormatCommandCommon.FormatAsync(FormatOptions formatOptions, ILogger`1 logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.Commands.RootFormatCommand.FormatCommandDefaultHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)
   at System.CommandLine.Invocation.InvocationPipeline.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)

See detailed reports in MegaLinter artifacts
Set VALIDATE_ALL_CODEBASE: true in mega-linter.yml to validate all sources, not only the diff

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 11, 2026

Greptile Summary

This PR expands CQRS benchmark coverage with four new benchmark classes (notification lifetime, notification cold-start, request cold-start, and stream cold-start), and hardens the generated invoker descriptor validation pipeline in CqrsHandlerRegistrar to handle exceptions, null returns, null entries, duplicate keys, and provider cross-validation mismatches during descriptor enumeration.

  • CqrsHandlerRegistrar: RegisterGeneratedRequestInvokerDescriptors and its stream counterpart now wrap GetDescriptors() in a try/catch, guard against null return values and null individual entries, validate each descriptor by cross-checking with TryGetDescriptor, and use a per-call HashSet<InvokerDescriptorKey> to prevent intra-enumeration duplicate writes to the dispatcher's global cache.
  • Tests: New test cases cover the added validation paths, multi-publisher rejection, publisher caching, and shared-binding/pipeline-executor laziness.
  • Benchmarks: Four new benchmark files covering notification lifetime, and cold-start costs for notifications, requests, and streams.

Confidence Score: 5/5

Safe to merge; changes are additive and the registrar hardening only affects an edge-case validation path that source-generated providers would never trigger.

The registrar logic change is well-tested across all new edge cases. The one catch-block issue only manifests with pathologically malformed third-party providers, not the framework's own generated code. All other changed paths are additive test and benchmark code.

GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs — the catch blocks in TryValidateEnumeratedRequestInvokerDescriptor and TryValidateEnumeratedStreamInvokerDescriptor could themselves throw if a descriptor entry carries null type fields.

Important Files Changed

Filename Overview
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs Adds exception-safe descriptor enumeration, null-entry guards, and per-call duplicate detection for both request and stream invoker descriptors. The catch blocks in the two new validation helpers access descriptor type fields that could be null, which could cause the catch block itself to throw in malformed-provider scenarios.
GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs New benchmark comparing Singleton/Scoped/Transient handler lifetimes; _scopedContainer is now correctly passed to BenchmarkCleanupHelper.DisposeAll in Cleanup(), addressing the previously flagged disposal gap.
GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs Adds comprehensive edge-case tests for generated invoker descriptor enumeration: empty, throwing, null-returning, duplicate, mismatched, and invalid-first/valid-second scenarios for both request and stream paths.
GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs New tests for notification publisher selection and ambiguity detection, including multiple-publisher rejection and publisher caching after first publish.
GFramework.Cqrs.Benchmarks/Messaging/StreamStartupBenchmarks.cs New cold-start stream benchmark comparing reflection vs. source-generated invoker path and MediatR; uses IterationSetup to clear the dispatcher static cache outside measurement to isolate first-binding cost only.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[RegisterGeneratedRequestInvokerDescriptors] --> B{provider implements IEnumeratesCqrsRequestInvokerDescriptors?}
    B -- No --> Z[Return]
    B -- Yes --> C[Call GetDescriptors]
    C --> D{Throws?}
    D -- Yes --> E[Log Warn, Return]
    D -- No --> F{Returns null?}
    F -- Yes --> G[Log Warn, Return]
    F -- No --> H[For each descriptorEntry]
    H --> I{entry is null?}
    I -- Yes --> J[Log Warn, continue]
    I -- No --> K[Create InvokerDescriptorKey]
    K --> L[TryValidateEnumeratedRequestInvokerDescriptor]
    L --> M{TryGetDescriptor returns match?}
    M -- No/throws --> N[Log Warn, return false]
    M -- Yes --> O{InvokerMethod and HandlerType match?}
    O -- No --> P[Log Warn, return false]
    O -- Yes --> Q[return true]
    N --> R{valid?}
    P --> R
    Q --> R
    R -- false --> S[continue loop]
    R -- true --> T{registeredKeys.Add successful?}
    T -- No duplicate --> U[RegisterGeneratedRequestInvokerDescriptor to dispatcher global cache]
    T -- Duplicate --> V[Log Warn, continue]
    U --> H
    S --> H
    V --> H
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs:516-521
**Catch block can itself throw if descriptor entry has null types**

The catch block interpolates `descriptorEntry.RequestType.FullName` and `descriptorEntry.ResponseType.FullName` directly. If a malformed provider returned a `CqrsRequestInvokerDescriptorEntry` whose `RequestType` or `ResponseType` is null, `TryGetDescriptor` would throw (e.g., `ArgumentNullException`), the catch would be entered, and then the log message interpolation itself would throw a `NullReferenceException` that escapes the catch block uncaught — defeating the entire safety net. The same pattern is repeated in the catch block of `TryValidateEnumeratedStreamInvokerDescriptor` (line 561–566). Using null-conditional access like `descriptorEntry.RequestType?.FullName ?? "<null>"` in both catch blocks would make them unconditionally safe.

Reviews (2): Last reviewed commit: "fix(cqrs): 收口 PR review 剩余问题" | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md`:
- Around line 15-17: Update the inconsistent PR anchor references: find every
occurrence of the string "PR `#347`" in this document (notably the active PR 锚点 at
the recovery entry showing `CQRS-REWRITE-RP-133` / `Phase 8` and the active
trace section around line 49) and change them to "PR `#348`" so the recovery point
and active trace match the current PR; verify there are no remaining "PR `#347`"
instances elsewhere in the file to ensure all tracking anchors are synchronized.

In `@GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs`:
- Around line 144-183: The three public benchmark methods
PublishNotification_Baseline, PublishNotification_GFrameworkCqrs, and
PublishNotification_MediatR (and the public Handle(...) mentioned) only have
<summary> XML docs — add missing <param> and <returns> XML tags to each method:
document the method parameters (e.g., the notification parameter and
CancellationToken when applicable or the implicit BenchmarkContext usage) with
<param name="..."> and describe the return type with <returns> (ValueTask or
Task), and include any relevant <remarks> or <exception> if applicable; also
apply the same <param>/<returns> additions to the other public methods noted
around lines 296–301 so all public/protected/internal members follow the XML
documentation contract.
- Around line 52-68: The HandlerLifetime enum lacks the repository-standard
[GenerateEnumExtensions] attribute; add [GenerateEnumExtensions] immediately
above the public enum HandlerLifetime declaration so the generated enum
extension methods are produced for Singleton/Scoped/Transient and keep enum
usage consistent with other enums.

In `@GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs`:
- Around line 360-371: The code currently adds the InvokerDescriptorKey to
registeredKeys before validation, which can drop a later valid descriptor if the
first with the same key fails validation; change the flow so that you first call
TryValidateEnumeratedRequestInvokerDescriptor(provider, descriptorEntry,
assemblyName, logger) and only if it returns true attempt to add the new
InvokerDescriptorKey(descriptorEntry.RequestType, descriptorEntry.ResponseType)
to registeredKeys, logging and continuing on duplicates; apply the same change
to the analogous stream-path validation (the other block that follows the
TryValidate... stream validator) so de-duplication happens after successful
validation.
- Around line 504-506: The comparison using ReferenceEquals on MethodInfo is
incorrect; replace ReferenceEquals(resolvedDescriptor.InvokerMethod,
descriptorEntry.Descriptor.InvokerMethod) with an equality check (use == or
.Equals) so MethodInfo instances that are equivalent across reflection calls are
treated as equal; update both occurrences around the conditional that involves
resolvedDescriptor.InvokerMethod and descriptorEntry.Descriptor.InvokerMethod in
CqrsHandlerRegistrar (also mirror the same change at the other comparison near
lines 549-551) so TryGetDescriptor returned descriptors are not erroneously
rejected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 95b0e463-1e09-408e-8754-892a16814bb4

📥 Commits

Reviewing files that changed from the base of the PR and between 3b2e689 and babd132.

📒 Files selected for processing (19)
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/README.md
  • GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsRegistrationServiceTests.cs
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.Cqrs/README.md
  • ai-plan/public/cqrs-rewrite/archive/todos/cqrs-rewrite-migration-tracking-history-through-rp131.md
  • ai-plan/public/cqrs-rewrite/archive/traces/cqrs-rewrite-migration-trace-history-through-rp131.md
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • docs/zh-CN/core/command.md
  • docs/zh-CN/core/cqrs.md
  • docs/zh-CN/core/query.md
  • docs/zh-CN/source-generators/cqrs-handler-registry-generator.md
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (C#)
  • GitHub Check: Code Quality & Security
  • GitHub Check: Build and Test
🧰 Additional context used
📓 Path-based instructions (13)
ai-plan/public/**

📄 CodeRabbit inference engine (AGENTS.md)

ai-plan/public/**: Contributors MUST keep committed ai-plan/public/** content safe to publish in Git history
Active tracking and trace files are recovery entrypoints, not append-only changelogs. They MUST stay concise enough for boot to locate the current recovery point quickly
When completed and validated stages begin to accumulate, contributors MUST archive their detailed history out of the active todos/ and traces/ entry files in the same change. Keep only the current recovery point, active facts, active risks, immediate next step, and pointers to the relevant archive files in the default boot path
When a topic is fully complete, move the entire topic directory under ai-plan/public/archive/<topic>/ and remove it from ai-plan/public/README.md in the same change
When a task spans multiple commits or is likely to exceed a single agent context window, update both the recovery document and the trace at each meaningful milestone before pausing or handing work off
If subagents are used on a complex task, the main agent MUST capture the delegated scope and any accepted findings in the active recovery document or trace before continuing implementation

Files:

  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • ai-plan/public/cqrs-rewrite/archive/traces/cqrs-rewrite-migration-trace-history-through-rp131.md
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/archive/todos/cqrs-rewrite-migration-tracking-history-through-rp131.md
ai-plan/**

📄 CodeRabbit inference engine (AGENTS.md)

ai-plan/**: Never write secrets, tokens, credentials, private keys, machine usernames, home-directory paths, hostnames, IP addresses, proprietary URLs, or other sensitive environment details into any ai-plan/** file
Never record absolute file-system paths in ai-plan/**; use repository-relative paths, branch names, PR numbers, or stable document identifiers instead

Files:

  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • ai-plan/public/cqrs-rewrite/archive/traces/cqrs-rewrite-migration-trace-history-through-rp131.md
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/archive/todos/cqrs-rewrite-migration-tracking-history-through-rp131.md
ai-plan/public/**/traces/**

📄 CodeRabbit inference engine (AGENTS.md)

Contributors MUST maintain a matching execution trace under ai-plan/public/<topic>/traces/ for complex work. The trace should record the current date, key decisions, validation milestones, and the immediate next step

Files:

  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • ai-plan/public/cqrs-rewrite/archive/traces/cqrs-rewrite-migration-trace-history-through-rp131.md
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation should be organized with Chinese content in docs/zh-CN/ and structured to include getting started, module-specific capabilities (Core, Game, Godot, ECS), source generator usage, tutorials, best practices, and troubleshooting

Files:

  • docs/zh-CN/core/query.md
  • docs/zh-CN/core/command.md
  • docs/zh-CN/source-generators/cqrs-handler-registry-generator.md
  • docs/zh-CN/core/cqrs.md
{README.md,docs/**}

📄 CodeRabbit inference engine (AGENTS.md)

{README.md,docs/**}: Update the relevant README.md or docs/ page when behavior, setup steps, architecture guidance, or user-facing examples change
Public documentation under README.md and docs/ MUST stay reader-facing. Do not publish governance-only content such as inventory tables, coverage baselines, review queues, batch metrics, recovery points, trace summaries, or "this still needs a later audit wave" notes
Public documentation MUST use semantic section titles and link labels. Do not surface raw filenames or paths such as README.mdgame/index.md../core/cqrs.md as reader-facing navigation text when a meaningful destination label is available
Public documentation MUST avoid rhetorical, self-referential, or AI-sounding headings and prompts. Prefer neutral labels instead of phrases like "你真正会用到的公开入口"、"先理解包关系"、"这个栏目应该回答什么" or "想看……转到……"
Public documentation MUST present limitations, suitability, and migration boundaries as adoption guidance for readers. Do not publish internal-governance or product-roadmap wording in README.md or docs/**; that material belongs in ai-plan/**

Files:

  • docs/zh-CN/core/query.md
  • docs/zh-CN/core/command.md
  • docs/zh-CN/source-generators/cqrs-handler-registry-generator.md
  • docs/zh-CN/core/cqrs.md
docs/**

📄 CodeRabbit inference engine (AGENTS.md)

docs/**: The main documentation site lives under docs/, with Chinese content under docs/zh-CN/
Keep code samples, package names, and command examples aligned with the current repository state
Prefer documenting behavior and design intent, not only API surface
When a public page references XML docs or API coverage, convert that evidence into reader-facing guidance: explain which types, namespaces, or entry points readers should inspect and why, instead of exposing audit counts or governance terminology
If an existing documentation page no longer reflects the current implementation, fixing the code without fixing the documentation is considered incomplete work
Do not rely on "the code is self-explanatory" for framework features that consumers need to adopt; write the adoption path down so future users do not need to rediscover it from source
When examples are rewritten, preserve only the parts that remain true. Delete or replace speculative examples instead of lightly editing them into another inaccurate form

Files:

  • docs/zh-CN/core/query.md
  • docs/zh-CN/core/command.md
  • docs/zh-CN/source-generators/cqrs-handler-registry-generator.md
  • docs/zh-CN/core/cqrs.md
docs/zh-CN/**

📄 CodeRabbit inference engine (AGENTS.md)

docs/zh-CN/**: When a feature is added, removed, renamed, or substantially refactored, contributors MUST update or create the corresponding user-facing integration documentation in docs/zh-CN/ in the same change
For integration-oriented features such as the AI-First config system, documentation MUST cover: project directory layout and file conventions, required project or package wiring, minimal working usage example, and migration or compatibility notes when behavior changes

Files:

  • docs/zh-CN/core/query.md
  • docs/zh-CN/core/command.md
  • docs/zh-CN/source-generators/cqrs-handler-registry-generator.md
  • docs/zh-CN/core/cqrs.md
**/Cqrs/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Use CQRS (Command Query Responsibility Segregation) pattern with the Cqrs naming entry point instead of the historical Mediator alias

Files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsRegistrationServiceTests.cs
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Apply [Log] attribute for automatic logging field and logging helper method generation
Apply [Priority] attribute for automatic priority comparison implementation generation
Apply [GenerateEnumExtensions] attribute to generate enumeration extension capabilities
Apply [ContextAware] attribute to automatically implement IContextAware boilerplate logic

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///)
XML documentation comments MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable, explaining intent, contract, and usage constraints instead of restating syntax
If a member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly in XML documentation
Add inline comments for non-trivial logic, concurrency or threading behavior, performance-sensitive paths, workarounds and compatibility constraints, edge cases, registration order, lifecycle sequencing, and generated code assumptions
Avoid obvious comments such as // increment i
Methods with non-trivial logic MUST document: The core idea, Key decisions, and Edge case handling, if any
Comments MUST NOT be trivial, redundant, or misleading. Prefer explaining why and when, not just what. Code should remain understandable without requiring external context. Prefer slightly more explanation over too little for framework code
Do not rely on implicit imports. Declare every required using explicitly
Write null-safe code that respects nullable annotations instead of suppressing warnings by default
Use the namespace pattern GFramework.{Module}.{Feature} with PascalCase segments
Follow standard C# naming: Types, methods, properties, events, and constants use PascalCase; Interfaces use I prefix; Parameters and locals use camelCase; Private fields use _camelCase
Use 4 spaces for indentation. Do not use tabs
Use Allman braces
Keep using directives at the top...

Files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationStartupBenchmarks.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsRegistrationServiceTests.cs
**/*.Tests/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.Tests/**/*.cs: Mirror the source structure in test projects whenever practical
Reuse existing architecture test infrastructure when relevant: ArchitectureTestsBase<T>, SyncTestArchitecture, AsyncTestArchitecture

Files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsRegistrationServiceTests.cs
ai-plan/public/**/todos/**

📄 CodeRabbit inference engine (AGENTS.md)

ai-plan/public/**/todos/**: When working from a tracked implementation plan, contributors MUST update the corresponding tracking document under ai-plan/public/<topic>/todos/ in the same change
Tracking updates MUST reflect completed work, newly discovered issues, validation results, and the next recommended recovery point
For any multi-step refactor, migration, or cross-module task, contributors MUST create or adopt a dedicated recovery document under ai-plan/public/<topic>/todos/ before making substantive code changes
Recovery documents MUST record the current phase, the active recovery point identifier, known risks, and the next recommended resume step so another contributor or subagent can continue the work safely

Files:

  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/archive/todos/cqrs-rewrite-migration-tracking-history-through-rp131.md
**/*{Startup,Init,Register,Setup,Configure}*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

CQRS handler registration should use generated products from CqrsHandlerRegistryGenerator at runtime, falling back to reflection scanning when generation cannot cover cases; explicitly register handlers from non-default assemblies using RegisterCqrsHandlersFromAssembly(...) or RegisterCqrsHandlersFromAssemblies(...)

Files:

  • GFramework.Cqrs.Benchmarks/Messaging/NotificationStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestStartupBenchmarks.cs
**/README.md

📄 CodeRabbit inference engine (AGENTS.md)

**/README.md: Use the canonical filename README.md. Do not introduce new ReadMe.md or other filename variants
A module README MUST describe: the module's purpose, the relationship to adjacent runtime, abstractions, or generator packages, the major subdirectories or subsystems the reader is expected to use, the minimum adoption path, and the corresponding docs/zh-CN/ entry points
If a module's responsibilities, setup, public API surface, generator inputs, or adoption path change, update that module's README.md in the same change

Files:

  • GFramework.Cqrs.Benchmarks/README.md
  • GFramework.Cqrs/README.md
🧠 Learnings (1)
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationStartupBenchmarks.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestStartupBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/NotificationLifetimeBenchmarks.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsRegistrationServiceTests.cs
🪛 LanguageTool
docs/zh-CN/source-generators/cqrs-handler-registry-generator.md

[uncategorized] ~93-~93: 数词与名词之间一般应存在量词,可能缺少量词。
Context: ...数据为空、只保留 marker 语义,或 registry 整体不可用时,才退回整程序集补扫 8. 同一程序集按稳定键去重,避免重复注册 这个行为由 [运行时注册流...

(wa5)


[uncategorized] ~132-~132: 您的意思是“"不"齐”?
Context: ...,才允许发射依赖 fallback 的结果 fallback 在这里表示“补齐生成注册器没有直接接线的剩余 handler”,不是“生成器一出现就重新扫描整...

(BU)

GFramework.Cqrs/README.md

[uncategorized] ~121-~121: 您的意思是“"不"齐”?
Context: ...time 并接线默认注册流程;只有在裸容器、测试宿主或自定义组合根里,才需要显式补齐 runtime、publisher 策略或额外程序集注册。 ## 运行时行...

(BU)


[uncategorized] ~141-~141: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:快"地"分发
Context: ...察失败”的场景,而不是把 publish 切成另一条 generated 或更快的分发通道。 如果你需要显式保留默认顺序语义,也可以在组合根里直接声明: ``...

(wb4)


[uncategorized] ~200-~200: 数词与名词之间一般应存在量词,可能缺少量词。
Context: ...。 - CqrsReflectionFallbackAttribute 可以多次声明,并同时承载 Type[]string[] 两类 fallback...

(wa5)


[uncategorized] ~201-~201: 数词与名词之间一般应存在量词,可能缺少量词。
Context: ... marker、空 fallback 元数据,或生成注册器整体不可用时,才会退回整程序集扫描。 - 处理器以 transient 方式注册,避免上下文感知处理器在并发...

(wa5)


[uncategorized] ~204-~204: 您的意思是“"不"齐”?
Context: ...ore` 架构初始化路径,这些步骤通常由框架自动完成;裸容器或测试环境则需要显式补齐 runtime 与注册入口。 ## 适用边界 - 这个包是默认实现,不是...

(BU)

ai-plan/public/cqrs-rewrite/archive/todos/cqrs-rewrite-migration-tracking-history-through-rp131.md

[uncategorized] ~11-~11: 您的意思是“"不"读”?
Context: ... active todos/traces/,再从 archive 补读所需历史。 - 若只需要历史结论,优先查本文件的阶段索引;若需要当轮验证细节、...

(BU)

🔇 Additional comments (14)
docs/zh-CN/core/command.md (1)

112-151: 兼容入口与迁移边界写得很清楚。

这段把 bridge、fallback 条件和“继续保留/开始迁移”的判断标准都落到了可执行层面,便于读者直接决策。

GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs (2)

94-156: 新增通知发布器歧义与缓存测试覆盖到位。

多发布器冲突和首次解析后复用这两条关键路径都被明确断言,回归保护价值很高。


329-347: PublishCallCount 的引入很实用。

计数属性与递增逻辑让缓存复用断言更直接,也避免了仅靠布尔状态带来的歧义。

GFramework.Cqrs.Tests/Cqrs/CqrsRegistrationServiceTests.cs (2)

90-176: 程序集键回退路径测试补得很扎实。

FullNameName 缺失链路都覆盖到了,并且校验了跨调用去重行为。


184-208: CreateAssembly 的可配置退化模型设计合理。

这个重载把测试意图从“构造 mock 细节”里解耦出来,后续扩展类似场景会更轻松。

GFramework.Cqrs.Benchmarks/Messaging/RequestStartupBenchmarks.cs (1)

20-260: 第三组 Mediator 基线接入完整。

初始化与冷启动两组都补齐了,并且服务提供器生命周期也同步纳入清理逻辑,基准可比性更强。

GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs (2)

312-872: 共享 binding 下“零行为→有行为”切换场景覆盖非常关键。

这些新增用例把 executor 延迟创建与上下文重新注入的边界都钉住了,能有效防止缓存路径回归。


873-1008: DispatcherCacheFixtureOptions 的引入很加分。

通过可选注册开关来组合测试形状,明显提升了夹具表达力和后续可维护性。

GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs (2)

451-569: 生成描述符异常/重复/不一致三类回退用例补得很全面。

这组测试把 provider 预热边界行为覆盖得很完整,能很好约束 runtime fallback 的稳定性。


983-1357: 这些测试用 registry 替身设计清晰且贴合场景。

每种异常形态都有独立实现,断言来源明确,后续定位失败原因会很直接。

docs/zh-CN/source-generators/cqrs-handler-registry-generator.md (1)

43-148: generated invoker 覆盖边界与 fallback 语义说明很到位。

“只覆盖 request/stream、notification 仍走 publisher 策略”以及回退触发条件都讲清楚了,和采用决策直接相关。

docs/zh-CN/core/query.md (1)

88-127: 旧查询兼容入口与 CQRS bridge 的关系描述清晰。

回退条件、适用场景和迁移判断都给到了可操作标准,能降低存量项目迁移歧义。

GFramework.Cqrs.Benchmarks/Messaging/NotificationStartupBenchmarks.cs (1)

63-98: 基准分组与生命周期管理实现清晰

Initialization/ColdStart 分组边界明确,迭代缓存重置与全局资源释放完整,便于稳定对比三条宿主路径。

Also applies to: 132-169

GFramework.Cqrs.Benchmarks/Messaging/StreamStartupBenchmarks.cs (1)

138-181: 三路径冷启动对照实现完整且边界一致

每条 cold-start 路径都采用“新宿主 + 首元素命中”的一致测量方式,配合 generated registry 描述符实现,结果可比性很好。

Also applies to: 337-429

Comment thread ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md Outdated
Comment thread GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs Outdated
Comment thread GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs Outdated
@GeWuYou GeWuYou changed the title Feat/cqrs optimization Feat/Enhance CQRS benchmarks coverage and generated invoker descriptor validation May 11, 2026
- 修复 NotificationLifetimeBenchmarks 的 scoped 容器释放与公开 XML 契约缺口

- 修复 generated descriptor 预热阶段先去重后校验导致的有效后继条目丢失问题

- 更新 generated descriptor 的 MethodInfo 比较方式并补充 request/stream 回归测试

- 同步 cqrs-rewrite active tracking 与 trace 的当前 PR 锚点到 PR #348
@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2369    ↑2 2369    ↑2 0 0 0 0 37.0s    ↓54ms

Test Results

passed 2369 passed ↑2

Details

tests 2369 tests ↑2
clock 37.0s ↓54ms
tool nunit
build CI - Build & Test arrow-right build-and-test link #1108
pull-request Feat/Enhance CQRS benchmarks coverage and generated invoker descriptor validation link #348

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2256 0 3 4.8s

Fail Rate

Fail Rate 0.00%
Test 📝 Results 📊 Passed ✅ Failed ❌ Fail Rate (%) 📈
CreateStream_Should_Throw_When_Stream_Pipeline_Behavior_Context_Does_Not_Implement_IArchitectureContext 17 16 1 5.88    ↓0.37
PublishAsync_Should_Stop_After_First_Handler_Exception_When_Using_Default_Publisher 35 34 1 2.86    ↓0.08
PublishAsync_Should_Throw_When_Context_Does_Not_Implement_IArchitectureContext 39 38 1 2.56    ↓0.07

build-and-test: Run #1108

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2369 2369 0 0 0 0 0 37.0s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 35 4.1s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 50 1.2s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 50 2.2s 2.3s
Generates_Scene_Behavior_Boilerplate 50 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 50 1.1s 1.1s
Append_ShouldNotBlock 50 1.0s 1.0s
Context_Caching_Should_Improve_Performance 50 781ms 794ms
PendingCount_ShouldReflectQueuedEntries 50 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 50 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 50 401ms 402ms

± Comparison with run #1107 at c9d5ef8 | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 50 runs.

Github Test Reporter by CTRF 💚

@GeWuYou GeWuYou merged commit ef4d3d5 into main May 11, 2026
7 checks passed
@GeWuYou GeWuYou deleted the feat/cqrs-optimization branch May 11, 2026 09:33
@coderabbitai coderabbitai Bot mentioned this pull request May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant