Skip to content

feat: add multi-cluster contract routing#11

Merged
SunSi12138 merged 12 commits into
devfrom
feature/issue-10-multi-cluster
Jul 23, 2026
Merged

feat: add multi-cluster contract routing#11
SunSi12138 merged 12 commits into
devfrom
feature/issue-10-multi-cluster

Conversation

@SunSi12138

Copy link
Copy Markdown
Owner

Closes #10

Summary

Implements the 0.7.10 multi-cluster client coordinator. A contract is routed to exactly one named child SharpLinkClient when Get<TContract>() creates its proxy; the proxy then calls that child directly without coordinator lookup or cluster metadata on the RPC path.

Issue mapping

Issue area Implementation and coverage
Multi-cluster topology and limits SharpLinkMultiClusterClientBuilder, SharpLinkMultiClusterOptions, and SharpLinkMultiClusterClient; child slots retain ordinary fixed, endpoint-cluster, and resolver configurations. Unit coverage: SharpLinkMultiClusterClientTests.
Unique Get-time routing Immutable route snapshots in SharpLinkMultiClusterClient; static route and proxy-routing tests verify one-time contract selection and no child leakage.
Generated static routing and NativeAOT SharpLinkClusterContractAssemblyAttribute, SharpLinkGeneratedClusterRouteManifest, and generator analysis/emission; generator tests cover valid, duplicate, conflicting, and invalid declarations. SharpLink.AotSmoke routes two independent static contracts to orders and payments.
Dynamic registration lifecycle Explicit-cluster register, unregister, and replace delegation plus coordinator-owned route publication; runtime assembly integration tests cover conflict handling, rollback, drain, replace, and collectible contexts.
Isolation and lifecycle races Separate child runtimes and manifest projections, bounded concurrent connect, failure cleanup, stop/connect races, and stale type-route removal are exercised by multi-cluster unit and integration coverage.
Hosting ISharpLinkMultiClusterClientAccessor, accessor implementation, hosted service, and HostExtensions registration.
Compatibility/docs Normal SharpClientBuilder.Build() retains global manifest behavior; generated child contexts receive only their assigned closure. README, changelog, migration, architecture, and performance documentation describe API, limits, and compatibility.

Local validation on 804178c752d2532e35940b49687437640f3172dc

  • dotnet build Sharplink.slnx --no-restore -c Release -v minimal - passed, 0 warnings / 0 errors
  • dotnet test --project test/SharpLink.UnitTests/SharpLink.UnitTests.csproj -c Release --no-build - 294 passed
  • dotnet test --project test/SharpLink.Generator.Tests/SharpLink.Generator.Tests.csproj -c Release --no-build - 48 passed
  • dotnet run -c Release --no-build --project test/SharpLink.IntegrationTests -- --timeout 60s - passed serially
  • dotnet publish test/SharpLink.AotSmoke/SharpLink.AotSmoke.csproj -c Release -r osx-arm64 -o artifacts/aot-issue-10 followed by SharpLink.AotSmoke - AOT_SMOKE_PASS transport=tcp, including two static multi-cluster slots
  • dotnet pack Sharplink.slnx --no-build --no-restore -c Release -o artifacts/nuget then PackageSmoke restored from the generated packages using a new NUGET_PACKAGES cache - passed
  • 120-second SharedMemory Chaos - passed: 11 restarts, 419,825 successes, 152,123 expected failures, 0 unexpected failures, and all final gauges at zero

Performance-gate status

doc/performance-0.7.10.md records a five-round, alternating local fixed-TCP c32 P1 diagnostic sample against bfb26f0ba40c980a59e621d0a549399d7c444fba. Its median is 97.38% baseline QPS and 105.80% baseline P99, so it does not satisfy the strict P1 release gate. The full P1 transport/concurrency and allocation matrix, P2 direct-child comparison, P3 writer-pressure isolation run, and P4 2/8/16-slot resource measurements remain required on a stable release host. This PR makes no release-gate-passed claim.

@SunSi12138

Copy link
Copy Markdown
Owner Author

@codex review

@sunsi-agent

Copy link
Copy Markdown

CI is green on 804178c. @codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 804178c752

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
@SunSi12138

Copy link
Copy Markdown
Owner Author

Addressed the latest Codex findings in daa86f7:

  • coordinator cleanup now continues after caller cancellation for unregister and replacement;
  • deferred unregister recognizes a child release that already completed;
  • added regression coverage for all three paths.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: daa86f7843

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpLinkMultiClusterClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
@SunSi12138

Copy link
Copy Markdown
Owner Author

Fixed the intermittent EarlyServerResponseShouldRetainOnlyTheActiveClientStreamProducer timeout in 4eaa138c11cf9684af012d3f49e4584b46c42304. The test now synchronizes the producer start and the server response while preserving the no-consume response path.

Validation: dotnet test --solution Sharplink.slnx --configuration Release --no-build (564 passed).

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4eaa1380f5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpLinkMultiClusterClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
Comment thread src/SharpLink.Client/SharpClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
@SunSi12138

Copy link
Copy Markdown
Owner Author

Fixed the three current review findings in 603fc67:

  • static route target modules are initialized before the generated-manifest snapshot; the AOT smoke test no longer needs its manual initializer call;
  • a shared multi-cluster connect is owned by client shutdown, while each caller only cancels its own wait;
  • routes are restored if a child rejects unregistration while it still retains the dynamic assembly.

Validation:

  • dotnet test --solution Sharplink.slnx --configuration Release --no-build — 566 passed
  • managed and NativeAOT AOT smoke — passed

@codex review

@SunSi12138

Copy link
Copy Markdown
Owner Author

Follow-up for 7f332c7:

  • multi-cluster replacement now publishes coordinator routes as soon as the child publishes, before old calls finish draining;
  • known UseEndpoint(...) slots now count their actual fixed-client pool budget, not the cluster default.

The remaining replacement-type-collision suggestion is addressed on its exact thread: valid coordinator state cannot reach it because ContractIds are globally unique at registration and replacement preserves the ID set.

Validation: dotnet test --solution Sharplink.slnx --configuration Release --no-build — 567 passed.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f332c7c0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClientBuilder.cs Outdated
@SunSi12138

Copy link
Copy Markdown
Owner Author

Addressed the current Codex findings in 142088c:

  • build only validates manifests reachable from configured static routes; unrelated stale manifests no longer block construction;
  • dependency manifests are resolved and initialized recursively in the routed assembly’s own AssemblyLoadContext, avoiding duplicate-identity cross-ALC binding;
  • deferred unregister cleanup polls the child registration state instead of repeatedly starting timed-out child unregister operations.

Validation:

  • dotnet test --solution Sharplink.slnx --configuration Release --no-build — 567 passed
  • NativeAOT AOT smoke — passed

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 142088ce5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpLinkClient.cs
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated

Copy link
Copy Markdown
Owner Author

Addressed the current Codex findings in 8df0956:

  • filtered multi-cluster children no longer build a runtime context from the process-wide manifest catalog before their explicit manifest closure is applied;
  • static route discovery filters to the coordinator’s configured clusters before loading manifests or validating routes, so unrelated live route manifests do not block construction;
  • dynamic registrations reserve their ContractIds while unregister is pending, and route restoration validates both runtime type and ContractId uniqueness.

Validation:

  • dotnet test --solution Sharplink.slnx --configuration Release --no-build — 570 passed
  • PR Quick integration command (--timeout 60s) — 225 passed in 27.5s
  • NativeAOT smoke — passed

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8df09569a0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpLinkMultiClusterClientBuilder.cs
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
Comment thread src/SharpLink.Hosting/SharpLinkMultiClusterClientAccessor.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated

Copy link
Copy Markdown
Owner Author

Addressed the current Codex findings in 667e4f1:

  • the coordinator no longer retains the route-catalog snapshot after building its manifest closure, so unrelated collectible route manifests remain collectible;
  • RegisterAssembly(cluster, null) now returns the shared structured InvalidArgument result, and unregistering a missing multi-cluster registration returns ReferencesReleased=false like a child client;
  • hosted multi-cluster publication, stop, and lookup are synchronized so shutdown cannot be followed by a new visible client publication.

Regression coverage includes collectible unconfigured route manifests, structured dynamic-registration results, and stopped accessor behavior.

Validation:

  • dotnet test --solution Sharplink.slnx --configuration Release --no-build — 573 passed
  • PR Quick integration command (--timeout 60s) — 225 passed in 27.8s
  • NativeAOT smoke — passed

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 667e4f1491

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated
Comment thread src/SharpLink.Client/SharpClientBuilder.cs Outdated

Copy link
Copy Markdown
Owner Author

Addressed the current Codex findings in d4f52f1:

  • shared connect now transitions to Ready or Faulted only with a compare-exchange from Connecting, so shutdown remains terminal even if a child connect completes afterwards;
  • dynamic registration checks the coordinator terminal state before slot lookup and returns the structured InvalidObjectState result after shutdown;
  • static endpoint collections are frozen once for multi-cluster preflight and construction, so a one-endpoint UseEndpoints(...) slot receives its fixed-client budget without re-enumerating the source.

Regression coverage exercises a child connect completing after stop, stopped dynamic registration, and one-shot one-endpoint collections.

Validation:

  • dotnet build Sharplink.slnx --configuration Release --no-restore --verbosity minimal — 0 warnings / 0 errors
  • dotnet test --solution Sharplink.slnx --configuration Release --no-build — 576 passed
  • PR Quick integration command (--timeout 60s) — 226 passed in 27.8s
  • NativeAOT smoke — passed

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4f52f14ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/SharpLink.Client/SharpClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated

Copy link
Copy Markdown
Owner Author

Addressed the current Codex findings in a3981f3:

  • the exact endpoint snapshot produced for multi-cluster preflight is now consumed by that one build and cleared before every BuildCore, preserving one-shot sources while ensuring later builder builds take a fresh topology snapshot;
  • ReplaceAssemblyAsync now checks terminal coordinator state before slot lookup and again before route mutation, returning the structured InvalidObjectState replacement result after shutdown.

Regression coverage verifies a builder uses updated endpoint data after a preflight build and that replacement after shutdown remains structured.

Validation:

  • dotnet build Sharplink.slnx --configuration Release --no-restore --verbosity minimal — 0 warnings / 0 errors
  • dotnet test --solution Sharplink.slnx --configuration Release --no-build — 578 passed
  • PR Quick integration command (--timeout 60s) — 226 passed in 27.7s
  • NativeAOT smoke — passed

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3981f3e4e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread doc/migration-0.7.10.md Outdated
Comment thread src/SharpLink.Client/SharpClientBuilder.cs Outdated
Comment thread src/SharpLink.Client/SharpLinkMultiClusterClient.cs Outdated

Copy link
Copy Markdown
Owner Author

本轮已集中处理最新三条反馈(当前头提交 bfb5a6df1447fb7f3bf2c47cae353dd4e62af52e):

  • 迁移文档改为准确描述:未配置槽位的路由会被忽略。
  • 静态多端点槽位的协调器预算按 min(MaxConnections, endpointCount × MaxConnectionsPerEndpoint) 预检,并新增回归覆盖。
  • 停止/终止状态下的动态注销在槽位查找前返回 ReferencesReleased = false,与子客户端的无操作语义一致,并新增回归覆盖。

本地验证:Release 构建 0 警告/0 错误;目标单测 15/15;完整解决方案测试 580/580;CI 同款 Quick 226/226;NativeAOT 烟测通过(AOT_SMOKE_PASS transport=tcp)。

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: bfb5a6df14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@SunSi12138
SunSi12138 merged commit 2dd4e84 into dev Jul 23, 2026
1 check passed
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.

2 participants