Skip to content

Feat/cqrs optimization#347

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

Feat/cqrs optimization#347
GeWuYou merged 5 commits into
mainfrom
feat/cqrs-optimization

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented May 11, 2026

Summary by CodeRabbit

发布说明

  • 新功能

    • 基准测试现已支持作用域(Scoped)处理器生命周期
    • 流式基准测试新增两种观察模式:仅消费第一项或完整枚举
    • 支持通过 --artifacts-suffix 并发运行基准测试,自动隔离输出目录
  • 文档

    • 更新了基准测试使用指南和配置说明

Review Change Stack

GeWuYou added 4 commits May 11, 2026 07:50
- 新增 FirstItem 与 DrainAll 两种 stream 观测模式,补齐 steady-state StreamingBenchmarks 的参数矩阵。

- 重构 stream 消费路径为共享 helper,分别覆盖首元素观测与完整枚举基线。
- 新增 StreamInvokerBenchmarks 的 FirstItem 与 DrainAll 双观测口径,并补齐相关 XML 注释。

- 引入 ScopedBenchmarkContainer 与 scoped request helper,为 RequestLifetimeBenchmarks 建立真实作用域边界下的 Scoped 生命周期矩阵。

- 更新 cqrs-rewrite 的 active tracking 与 trace,记录 RP-129 的多 worker 波次、串行化 smoke 验证与新的恢复入口。
- 新增真实 scoped stream benchmark helper,确保作用域覆盖完整枚举周期

- 扩展 StreamLifetimeBenchmarks 到 Singleton、Scoped、Transient 全矩阵并记录 scoped 结果

- 更新 benchmark README 与 cqrs-rewrite 恢复文档,收口当前验证结论与下一批方向
- 新增 benchmark 入口 artifacts suffix 解析与独立 host 工作目录重启逻辑

- 更新 benchmark README 并发运行约定,补充隔离命令示例

- 更新 cqrs-rewrite 恢复文档,记录并发验证结果与后续恢复点
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

Warning

Rate limit exceeded

@GeWuYou has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 59 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 23f90cae-a1b0-4db7-ac1c-15489df4acb2

📥 Commits

Reviewing files that changed from the base of the PR and between 0baa662 and 1420bd4.

📒 Files selected for processing (10)
  • GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Program.cs
  • GFramework.Cqrs.Benchmarks/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
📝 Walkthrough

走查

此PR为GFramework.Cqrs基准测试框架引入真正的请求级作用域生命周期支持,并实现基于命令行选项的并发运行自动隔离机制。通过新增作用域dispatch助手、容器适配器、流观察模式拆分、程序入口隔离逻辑,完整支持单机多进程并发基准执行。

变更

基准测试框架作用域隔离与并发支持

层级 / 文件 摘要
作用域dispatch基础设施
GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
添加四个新的作用域隔离dispatch方法(SendScopedGFrameworkRequestAsync、SendScopedMediatRRequestAsync、CreateScopedGFrameworkStream、CreateScopedMediatRStream)及两个私有async iterator辅助方法,支持per-request作用域的请求发送和流创建,并更新using指令以支持异步和集合API。
作用域容器适配器
GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs
实现ScopedBenchmarkContainer类适配IIocContainer,组合冻结根容器与单个请求scope的ServiceProvider。通过转发根容器查询、拦截变更操作、实现优先级排序的服务枚举,为消息基准提供只读的请求级别DI视图。
请求生命周期Scoped支持
GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
扩展HandlerLifetime枚举以包含Scoped选项。更新GlobalSetup条件性地创建运行时/mediator(仅非Scoped时)。修改benchmark方法根据Lifetime选择dispatch路径:Scoped时使用BenchmarkHostFactory新方法,否则使用预构建运行时。扩展handler注册和MediatR生命周期映射支持Scoped。
流观察模式拆分
GFramework.Cqrs.Benchmarks/Messaging/StreamInvokerBenchmarks.cs, GFramework.Cqrs.Benchmarks/Messaging/StreamingBenchmarks.cs
为两个benchmark类各引入StreamObservation枚举和Observation参数,支持FirstItem(单元素消费)和DrainAll(完整枚举)模式。重构benchmark方法通过共享ObserveAsync辅助方法进行消费控制,新增ConsumeFirstItemAsync和DrainAsync实现模式特定行为。更新XML文档反映观察语义。
流生命周期Scoped支持
GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs
扩展HandlerLifetime枚举以包含Scoped。添加运行时logger字段,更新Lifetime参数包含Scoped。在Setup中条件性地跳过运行时创建。修改三个benchmark方法检测Lifetime==Scoped分支,调用BenchmarkHostFactory的CreateScoped方法。扩展handler注册逻辑以支持RegisterScoped。
程序入口并发隔离
GFramework.Cqrs.Benchmarks/Program.cs
重构Main方法支持--artifacts-suffix命令行选项,实现ParseInvocation提取和验证suffix,ResolveArtifactsPath确定artifacts目录,ValidateArtifactsSuffix强制字符集限制。新增RunFromIsolatedHost创建隔离工作目录、递归复制输出、启动子进程实现并发隔离。更新using指令支持配置和文件操作。
文档和迁移追踪
GFramework.Cqrs.Benchmarks/README.md, ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md, ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
更新README以反映Scoped生命周期、观察模式拆分、并发运行指导(--artifacts-suffix隔离)。更新迁移跟踪文件恢复点为RP-131,描述artifacts-suffix隔离机制和验证结果。添加trace文件2026-05-11条目记录三个连续恢复阶段的执行结果。

预估代码审查工作量

🎯 4 (复杂) | ⏱️ ~45 分钟

可能相关的PR

  • GeWuYou/GFramework#345:主PR和该PR都修改了相同的CQRS基准和流/handler生命周期代码(添加作用域请求支持、流观察模式、作用域容器/dispatch助手),代码级别直接关联。
  • GeWuYou/GFramework#341:两个PR都修改BenchmarkHostFactory.cs以扩展基准主机/注册行为(该PR添加注册/启动助手和生成注册表接线,主PR添加作用域dispatch助手和scope支持的容器视图),相关联。
  • GeWuYou/GFramework#340:两个PR都涉及基准DI/主机管道改造,引入密切相关的API:PR #340添加了IIocContainer.HasRegistration和CreateMediatorServiceProvider助手,主PR实现了转发HasRegistration和在同一BenchmarkHostFactory文件中添加scoped Send/CreateScoped*助手的ScopedBenchmarkContainer,因此相关联。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning 标题「Feat/cqrs optimization」过于宽泛,未能准确反映此 PR 的主要变更内容。实际 PR 包含了多项重要功能:添加了作用域(Scoped)生命周期基准测试、流式观察模式(FirstItem/DrainAll)、并发基准测试隔离机制,以及相应的基础设施更新,但标题完全未体现这些具体改动。 建议将标题改为更具体的描述,例如「Add scoped handler lifetime and observation mode benchmarks with artifact isolation」或「Extend CQRS benchmarks with Scoped lifetime and multi-observation streaming」,以准确反映核心变更。
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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 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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 11, 2026

Greptile Summary

This PR expands the CQRS benchmark suite with three capabilities: (1) a Scoped handler lifetime dimension added to RequestLifetimeBenchmarks and StreamLifetimeBenchmarks, backed by the new ScopedBenchmarkContainer adapter that creates a real per-iteration DI scope; (2) FirstItem/DrainAll observation modes added to StreamingBenchmarks and StreamInvokerBenchmarks; and (3) an --artifacts-suffix mechanism in Program.cs that re-launches the benchmark host into an isolated directory so concurrent benchmark runs don't share the same BenchmarkDotNet auto-generated build folder.

  • ScopedBenchmarkContainer — new read-only IIocContainer adapter that wraps the frozen root MicrosoftDiContainer, routes resolution calls to an explicit per-benchmark-call IServiceScope, and throws for all mutation operations.
  • Scoped lifetime support — both request and stream lifetime benchmark classes now create ScopedBenchmarkContainer + ScopedRuntime only for the Scoped variant, leaving Singleton/Transient paths untouched.
  • Isolated host isolationProgram.cs validates and copies the current host directory to a suffix-namespaced folder, re-launches itself with the copied binary, and uses an environment variable sentinel to avoid re-launch loops.

Confidence Score: 5/5

Safe to merge — all changes are confined to the benchmark project and do not touch production runtime, DI, or test code.

The new ScopedBenchmarkContainer correctly routes resolution to per-iteration IServiceScope instances disposed via using-based leases. The isolated host relaunch mechanism is protected by ValidateIsolatedHostDirectory. The open items are limited to benchmark infrastructure cleanup ordering and have no effect on the correctness of measured results.

RequestLifetimeBenchmarks.cs, StreamLifetimeBenchmarks.cs, ScopedBenchmarkContainer.cs, and Program.cs carry the minor observations noted in the inline comments, but none block merging.

Important Files Changed

Filename Overview
GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs New 515-line adapter that wraps the frozen root container and routes Get/GetAll to an explicitly-created per-call IServiceScope; mutation methods throw; CreateScope() delegates to the scoped provider (not the root), which is a subtle semantic inconsistency if the runtime calls it internally.
GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs Adds four scoped dispatch helpers and two private async iterators; scope lifecycle is correctly managed with using-based ScopeLease / IServiceScope.
GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs Extends lifetime matrix to Scoped; creates ScopedBenchmarkContainer and scoped runtime only for the Scoped variant; GlobalCleanup disposes _container and _serviceProvider but omits explicit disposal of _scopedContainer.
GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs Extends stream lifetime matrix to Scoped; refactors Setup into focused private methods; GlobalCleanup similarly omits explicit disposal of _scopedReflectionContainer and _scopedGeneratedContainer.
GFramework.Cqrs.Benchmarks/Messaging/StreamInvokerBenchmarks.cs Adds FirstItem/DrainAll StreamObservation param and refactors benchmark methods to share ConsumeFirstItemAsync/DrainAsync helpers; no scoped lifetime changes.
GFramework.Cqrs.Benchmarks/Messaging/StreamingBenchmarks.cs Mirrors StreamInvokerBenchmarks: adds FirstItem/DrainAll observation mode, extracts ConsumeFirstItemAsync/DrainAsync helpers, no issues found.
GFramework.Cqrs.Benchmarks/Program.cs Adds --artifacts-suffix isolated host mechanism; ValidateIsolatedHostDirectory correctly guards against nesting but uses OrdinalIgnoreCase which is inconsistent with Path.GetRelativePath on Linux.
Prompt To Fix All With AI
Fix the following 4 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 4
GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs:143
`_scopedContainer` is created in `Setup()` when `Lifetime == HandlerLifetime.Scoped` but is not included in the `DisposeAll` call here. `ScopedBenchmarkContainer` implements `IDisposable`, so if an unhandled exception were to leave `_activeScope` non-null (e.g., a benchmark iteration threw before the `using` block disposed the `ScopeLease`), that scope would not be released at cleanup. Adding it to `DisposeAll` is the safest pattern to follow consistently with how the root containers are managed.

```suggestion
            BenchmarkCleanupHelper.DisposeAll(_container, _serviceProvider, _scopedContainer);
```

### Issue 2 of 4
GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs:140
`_scopedReflectionContainer` and `_scopedGeneratedContainer` are both `ScopedBenchmarkContainer` instances created when `Lifetime == HandlerLifetime.Scoped`, but neither is passed to `DisposeAll`. The same reasoning as in `RequestLifetimeBenchmarks` applies: if a benchmark iteration leaves an active scope open (e.g., via an uncaught exception), `Cleanup` will dispose the root containers without releasing the child scope held inside the adapters.

```suggestion
            BenchmarkCleanupHelper.DisposeAll(_reflectionContainer, _generatedContainer, _serviceProvider, _scopedReflectionContainer, _scopedGeneratedContainer);
```

### Issue 3 of 4
GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs:403-406
**`CreateScope()` returns a child of the active scope, not of the root**

When called while a scope is active, this delegates to `GetScopedProvider().CreateScope()`, which produces a nested scope rather than a fresh root-level scope. If the CQRS runtime ever calls `container.CreateScope()` internally during `SendAsync` or `CreateStream` (e.g., for pipeline behaviors that manage their own scope), those pipeline scopes become grandchildren of the benchmark-managed scope and could add invisible allocation overhead to the `Scoped` matrix rows.

### Issue 4 of 4
GFramework.Cqrs.Benchmarks/Program.cs:232-246
**Case-insensitive equality check is wrong on Linux**

The normalized path equality uses `StringComparison.OrdinalIgnoreCase`, which is correct on Windows but incorrect on Linux (case-sensitive filesystems). On Linux, `/tmp/Output` and `/tmp/output` are distinct directories; the guard would incorrectly report them as the same and throw. `Path.GetRelativePath` (used just below for the nesting check) uses `StringComparison.Ordinal` on Linux, making the two checks inconsistent on that platform.

Reviews (2): Last reviewed commit: "fix(cqrs): 修复 benchmark scoped 宿主与 PR 恢复..." | Re-trigger Greptile

Comment thread GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs Outdated
Comment thread GFramework.Cqrs.Benchmarks/Program.cs
@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2343 2343 0 0 0 0 38.1s    ↑1.5s

Test Results

passed 2343 passed

Details

tests 2343 tests
clock 38.1s ↑1.5s
tool nunit
build CI - Build & Test arrow-right build-and-test link #1104
pull-request Feat/cqrs optimization link #347

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2249 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 14 13 1 7.14    ↓0.55
PublishAsync_Should_Stop_After_First_Handler_Exception_When_Using_Default_Publisher 32 31 1 3.13    ↓0.10
PublishAsync_Should_Throw_When_Context_Does_Not_Implement_IArchitectureContext 36 35 1 2.78    ↓0.08

build-and-test: Run #1104

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

🎉 All tests passed!

Slowest Tests

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

± Comparison with run #1101 at 654bda9 | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 47 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.36s
✅ REPOSITORY gitleaks yes no no 8.52s
✅ REPOSITORY trufflehog yes no no 7.05s

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

@GeWuYou
Copy link
Copy Markdown
Owner Author

GeWuYou commented May 11, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 6

🤖 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 159-185: The "最近权威验证" section in
cqrs-rewrite-migration-tracking.md has accumulated repeated historical
verification lines and should be trimmed: move older benchmark/run/check entries
into a new archive file under ai-plan/public/archive (e.g.,
ai-plan/public/archive/cqrs-rewrite-migration-history.md), leaving only the
minimal current recovery point (the latest successful build/run summary) and the
immediate next steps in the active todos file; update the active file's "最近权威验证"
to reference the archive (link or short note) and remove redundant lines, and
ensure any referenced filenames like GFramework.Cqrs.Benchmarks/* remain in the
archive entries so the provenance is preserved.
- Around line 10-13: Summary: The markdown still uses a placeholder for the "当前
PR 锚点" instead of the real PR; replace it with the actual PR and keep tracking
accurate. Fix: edit the cqrs-rewrite-migration-tracking.md entry that contains
the field "当前 PR 锚点" and change its value from "待重新抓取" to the actual PR
reference "PR `#347`"; ensure the recovery point identifier `CQRS-REWRITE-RP-131`
and the phase `Phase 8` remain correct and that future updates to this file
always record the completed work, validation results, and the next recovery
point rather than placeholders.

In `@ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md`:
- Around line 3-91: The active trace file
ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md is growing
into an append-only changelog; trim it to only the current stage summary (e.g.
the "2026-05-11" header's key decision points, recent validations, and immediate
next steps) and move older, detailed phase-by-phase entries (the long "阶段:"
sections and per-benchmark validations) into ai-plan/public/archive/...; ensure
the top-level file keeps concise headings and a pointer/link to the new archive
files so reviewers can still find full history.

In `@GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs`:
- Around line 45-337: Add full XML documentation to all public members of
ScopedBenchmarkContainer (e.g., RegisterSingleton<T>,
RegisterSingleton<TService,TImpl>, RegisterTransient, RegisterScoped,
RegisterPlurality, RegisterSystem, Register, RegisterFactory,
RegisterCqrsPipelineBehavior, RegisterCqrsStreamPipelineBehavior,
RegisterCqrsHandlersFromAssembly(s), ExecuteServicesHook, Get<T>/Get(Type),
GetRequired<T>/GetRequired(Type), GetAll<T>/GetAll(Type), GetAllSorted<T>,
GetAllByPriority<T>/GetAllByPriority(Type), HasRegistration, Contains<T>,
ContainsInstance, Clear, Freeze, GetServicesUnsafe, CreateScope, SetContext,
GetContext, Dispose and CreateMutationNotSupportedException) by adding
appropriate /// <summary/> plus <param name="..."/>, <returns/>, and <exception
cref="..."/> tags where relevant (for example methods that throw
CreateMutationNotSupportedException should document the
InvalidOperationException), and use <remarks/> for any behavioral notes
(readonly scope semantics, delegation to _rootContainer/_scopedProvider). Ensure
signatures in the XML match generic/type parameter names and document null
argument checks (ArgumentNullException) for methods that validate inputs
(Get(Type), GetRequired(Type), GetAll(Type), HasRegistration(Type), etc.).

In `@GFramework.Cqrs.Benchmarks/Program.cs`:
- Around line 32-42: ParseInvocation currently only sets
invocation.ArtifactsSuffix from the CLI, so host isolation check using
invocation.ArtifactsSuffix misses cases where the suffix comes from the
environment (ResolveArtifactsPath). Modify ParseInvocation to also compute and
expose a boolean (e.g., Invocation.ShouldIsolateHost or
Invocation.ArtifactsSuffixEffective) that is true when an artifacts suffix is in
effect from either the command line or the
GFRAMEWORK_CQRS_BENCHMARK_ARTIFACTS_SUFFIX env var; then replace checks that
read invocation.ArtifactsSuffix (the RunFromIsolatedHost decision at the shown
block and the other sites around the 97-98 and 169-179 regions) to use the new
boolean so environment-provided suffixes trigger RunFromIsolatedHost and
consistent isolation behavior with ResolveArtifactsPath.
- Around line 109-116: 在调用 PrepareIsolatedHostDirectory
前加入检查以拒绝目标目录等于或位于源目录内部的配置:验证 artifactsPath / isolatedHostDirectory 与
sourceHostDirectory(AppContext.BaseDirectory)之间的路径关系,若 isolatedHostDirectory ==
sourceHostDirectory 或 isolatedHostDirectory 是 sourceHostDirectory 的子路径,则抛出
ArgumentException(或 ArgumentNullException 的合适替代)并给出清晰错误信息;在所有相关调用位置(包括上面片段用到的
variables artifactsPath、sourceHostDirectory、isolatedHostDirectory、以及文件中另一个相似片段
220-245)都应用相同校验以防止递归拷贝导致的 host/host/... 膨胀。
🪄 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: 14740b50-2795-4ce9-8df5-52738a07455c

📥 Commits

Reviewing files that changed from the base of the PR and between 699d0b4 and 0baa662.

📒 Files selected for processing (10)
  • GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamInvokerBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamingBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Program.cs
  • GFramework.Cqrs.Benchmarks/README.md
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.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.Benchmarks/Messaging/StreamingBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Program.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamInvokerBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs
  • GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.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
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/todos/cqrs-rewrite-migration-tracking.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/todos/cqrs-rewrite-migration-tracking.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/**/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
🧠 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.Benchmarks/Messaging/StreamingBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Program.cs
  • GFramework.Cqrs.Benchmarks/Messaging/StreamInvokerBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs
  • GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
🔇 Additional comments (7)
GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs (2)

178-219: request 级作用域边界处理得对。

每次发送都新建 scope,并在 scope 内解析 runtime / mediator,能避免 Scoped handler 退化成根容器解析,这和这组 benchmark 的建模目标是一致的。


222-273: 异步流的作用域生命周期处理正确。

using var scope 放进 async iterator 里是这里的关键点:无论是完整 drain、提前 break 还是异常退出,最终都会走到同一处释放逻辑,Scoped 依赖不会在建流后被提前销毁。

Also applies to: 309-350

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

161-218: 观测模式拆分与消费路径抽取实现清晰

ObserveAsync + ConsumeFirstItemAsync/DrainAsync 的分层让“首元素成本”和“全量枚举成本”边界非常明确,benchmark 可读性和可比性都更好。

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

157-185: Scoped 与非 Scoped 分发路径划分合理

Lifetime == Scoped 时切换到 BenchmarkHostFactory 的显式作用域 helper,非 Scoped 保持预建 runtime/mediator 直连,这个分流实现和 benchmark 语义一致。

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

204-267: Scoped stream 路径与观测消费路径衔接正确

Scoped 模式下通过 CreateScopedGFrameworkStream/CreateScopedMediatRStream 建流,再统一走 ObserveAsync 消费,作用域边界与观测口径都保持一致。

GFramework.Cqrs.Benchmarks/README.md (1)

59-74: 并发运行约束与用法示例更新到位

--artifacts-suffix 的并发隔离约定写得足够清楚,且和当前 benchmark 入口行为一致,能有效减少并发 smoke 的使用歧义。

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

189-247: ObserveAsync 抽象让 invoker 观测维度更可比

把首元素消费和全量消费统一收敛到共享 helper 后,四组 benchmark 方法的行为对齐更直接,后续读数解释成本更低。

Comment thread ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md Outdated
Comment thread ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md Outdated
Comment thread ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md Outdated
Comment thread GFramework.Cqrs.Benchmarks/Messaging/ScopedBenchmarkContainer.cs
Comment thread GFramework.Cqrs.Benchmarks/Program.cs
Comment thread GFramework.Cqrs.Benchmarks/Program.cs
- 修复 benchmark 入口的 artifacts 隔离判断与嵌套宿主目录保护,避免并发运行时宿主目录递归膨胀

- 优化 request 与 stream 生命周期 benchmark 的 scoped 宿主模型,复用单个 runtime 并仅在每次调用时创建真实 DI scope

- 补充 ScopedBenchmarkContainer 的 XML 合同说明,并收敛 README 与 ai-plan active 入口到当前 PR 恢复点
@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2343 2343 0 0 0 0 36.7s    ↓1.4s

Test Results

passed 2343 passed

Details

tests 2343 tests
clock 36.7s ↓1.4s
tool nunit
build CI - Build & Test arrow-right build-and-test link #1106
pull-request Feat/cqrs optimization link #347

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2251 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 15 14 1 6.67    ↓0.47
PublishAsync_Should_Stop_After_First_Handler_Exception_When_Using_Default_Publisher 33 32 1 3.03    ↓0.10
PublishAsync_Should_Throw_When_Context_Does_Not_Implement_IArchitectureContext 37 36 1 2.70    ↓0.08

build-and-test: Run #1106

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

🎉 All tests passed!

Slowest Tests

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

± Comparison with run #1104 at c50fd59 | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 48 runs.

Github Test Reporter by CTRF 💚

@GeWuYou GeWuYou merged commit 3b2e689 into main May 11, 2026
7 checks passed
@GeWuYou GeWuYou deleted the feat/cqrs-optimization branch May 11, 2026 04:25
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