Repository navigation
[Runtime Configuration][Client] Dynamic endpoint admission policy replacement #582
Description
Parent tracker: #262
Goal
Allow a running ISharpLinkClient to dynamically enable, replace, or disable a custom ISharpLinkEndpointAdmissionPolicy without rebuilding the Client.
This issue is intentionally narrow. SharpLink treats the custom policy as an application-owned black-box SPI and does not attempt to understand or migrate its internal state.
Runtime semantics
Supported modes:
Disabled
Custom(policy)
Supported transitions:
Disabled -> Custom A
Custom A -> Custom B
Custom A -> Disabled
The publication boundary is next endpoint attempt, not next logical call.
For every successfully acquired attempt:
Attempt captures Policy A
Policy A.TryAcquire(...) returns token A
runtime update publishes Policy B
attempt completes
Policy A.Report(outcome, token A)
A later attempt may capture Policy B.
TryAcquire and Report for one admitted attempt must always bind to the same captured policy instance/generation.
Scope
- runtime enable of a custom endpoint admission policy;
- runtime replacement of one custom policy with another;
- runtime disable;
- atomic publication for future attempts;
- capture the exact policy used by
TryAcquireand retain it until the attempt terminal report; - preserve the existing opaque policy-owned token unchanged;
- old admitted attempts continue to report to their captured old policy after replacement/disable;
- rejected attempts do not create a report lease;
- invalid/null publication is rejected without changing the current policy;
- update vs Stop/Dispose is deterministic;
- no request-path global lock;
- disabled healthy path retains the existing fast path and does not add per-attempt allocation solely for dynamic configuration;
- custom admission remains mutually exclusive with the built-in Circuit Breaker mode.
Explicitly out of scope
- custom policy option/configuration mutation by SharpLink;
- migration, cloning, serialization, reset, or reconciliation of application-owned policy state;
- per-endpoint dynamic configuration APIs;
- per-method dynamic configuration APIs;
- policy chaining/composition;
- asynchronous admission policies;
- changing the
ISharpLinkEndpointAdmissionPolicydecision/outcome contract; - Circuit Breaker parameter/state semantics (tracked separately under [Runtime Configuration] 动态配置 / Hot Reload 长期跟踪 #262);
- topology/load-balancing redesign.
Applications that need fine-grained dynamic rules inside one custom policy may keep the same policy object and implement their own immutable configuration snapshot internally; SharpLink does not manage that internal control plane.
Correctness invariants
- One admitted endpoint attempt owns exactly one captured admission policy reference and one opaque token.
- The policy that grants an attempt is the only policy that receives its terminal
Report. - Replacing or disabling the current policy cannot redirect an old attempt's terminal report to a newer policy.
- Old policy instances remain strongly reachable only while outstanding admitted attempts still need to report to them; SharpLink must not retain retired policies indefinitely after drain.
- Report exceptions remain isolated according to the existing contract and cannot corrupt pending-call terminal ownership.
- No second attempt completion state machine or pending registry is introduced.
Validation
At minimum cover:
- disabled -> custom;
- custom A -> custom B;
- custom -> disabled;
- update between
TryAcquireand attempt terminal completion; - update while a retrying logical call is between attempts: old attempt reports to old policy, next attempt may use new policy;
- rejected attempt around publication boundary;
- policy
TryAcquirethrow; - policy
Reportthrow; - caller cancellation/deadline/connection-close/GoAway/send-failure terminal outcomes;
- concurrent repeated replacements;
- update vs Stop/Dispose;
- retired policy released after outstanding reports drain;
- healthy admission-disabled allocation/performance gate.
Completion
This issue is complete when custom endpoint admission can be atomically enabled/replaced/disabled for future attempts while every outstanding admitted attempt remains permanently paired with the exact policy/token generation that admitted it.
Activity
SunSi12138 commentedon Sep 8, 2026
Implemented and reviewed in #596, now squash-merged into
devas8f40d8fa84dadddb52d301a15881a6c9123e83ab. The runtime endpoint-admission publication keeps the request path lock-free, binds each admitted attempt to the exact policy/token that granted it, re-evaluates admission at retry-attempt boundaries, preserves custom/circuit-breaker mutual exclusion, and rejects publication after shutdown begins. Final PR Fast rerun, PR Extended, CodeQL, and pending/codec validation are green. Closing as completed.