Skip to content

[Runtime Configuration][Client] Dynamic global retry policy #579

Closed

Description

@SunSi12138

Parent tracker: #262
Related retry foundation: #402
Related deadline/lifetime foundation: #287

Goal

Allow one running ISharpLinkClient instance to update its client-wide retry policy without rebuilding or replacing the Client.

This is a next-logical-call policy. A logical RPC captures one retry generation when it starts and keeps that generation across all of its attempts.

Runtime semantics

Support three client-wide retry modes:

Disabled
BuiltIn
Custom

Built-in mode keeps the existing bounded retry controls:

MaxAttempts
InitialBackoff
MaxBackoff
JitterRatio

Custom mode keeps framework ownership of attempts, deadlines, endpoint selection, pending calls and cancellation. ISharpLinkRetryPolicy only decides, after a failed eligible attempt:

ShouldRetry
Delay

Custom policy must remain bounded by a framework-owned MaxAttempts; it cannot create unbounded retries.

An update affects only logical calls that start after publication:

Call A captures retry generation N
runtime update publishes generation N+1
all attempts of A continue using generation N
Call B captures generation N+1

Existing retry eligibility remains unchanged

Runtime enablement does not make every call retryable:

[Idempotent] Unary -> eligible
non-idempotent Unary -> never retry
Streaming -> never retry
OneWay -> never retry

The existing built-in retryable error classification remains unchanged unless a separate issue explicitly changes it.

Relationship with request timeout

Retry and the client-wide request-timeout policy are independently configurable.

  • Retry may be enabled while the client-wide timeout fallback is disabled.
  • MaxAttempts still bounds retry count when no logical-call deadline exists.
  • If a logical-call deadline exists from any existing source, all attempts and backoff share that one remaining budget.
  • DeadlineExceeded terminates the logical call and is not itself a retryable attempt outcome under the current model.
  • Per-attempt timeout is out of scope.

Scope

  • runtime disable of retry;
  • runtime enable/update of built-in retry;
  • runtime update of MaxAttempts, InitialBackoff, MaxBackoff, JitterRatio;
  • runtime replacement with a custom ISharpLinkRetryPolicy plus framework-owned attempt bound;
  • custom -> built-in / built-in -> custom / any -> disabled transitions;
  • full candidate validation before atomic publication;
  • one retry generation captured per logical call;
  • all attempts of one logical call use the same captured generation;
  • update vs Stop/Dispose race semantics;
  • no new allocation/lock on retry-disabled healthy unary fast path;
  • preserve existing endpoint-admission/circuit-breaker ownership; that subsystem remains separate.

Explicitly out of scope

  • changing [Idempotent] dynamically;
  • adding retry to Streaming or OneWay;
  • changing the existing built-in retryable error set;
  • per-attempt timeout;
  • endpoint admission / circuit-breaker dynamic policy;
  • topology/load-balancing dynamic configuration;
  • caller-provided custom retry code executing RPC attempts itself;
  • unbounded retry.

Correctness invariants

  1. A logical call captures one complete retry policy before its first attempt.
  2. A runtime update cannot change retry count/backoff/decision policy halfway through an existing logical call.
  3. Retry count remains bounded by MaxAttempts, including the first attempt.
  4. Existing deadline/cancellation/Client Stop semantics remain authoritative and can terminate retry early.
  5. Invalid built-in options or invalid custom policy publication leave the current generation unchanged.
  6. Custom policy failures fail only the affected logical call according to the existing failure contract; they do not corrupt Client state.
  7. No second pending table, attempt registry, or endpoint state machine is introduced.

Validation

At minimum cover:

  • disabled -> built-in;
  • built-in parameter update;
  • built-in -> disabled;
  • built-in -> custom;
  • custom -> built-in/custom replacement;
  • invalid option rollback;
  • update while a retrying call is between attempts;
  • old call uses old generation while a new call uses the new generation;
  • retry enabled with global request timeout disabled;
  • retry with an existing logical-call deadline;
  • caller cancellation / Stop during backoff;
  • concurrent repeated updates;
  • retry-disabled healthy unary allocation/performance gate.

Completion

This issue is complete when a running Client can atomically replace its global retry behavior for future logical calls while every in-flight logical call remains bound to the retry generation it captured at start.

Activity

  1. SunSi12138 commented on Sep 7, 2026

    @SunSi12138
    OwnerAuthor

    Review pass for #594: no engineering-value issues found. After #593 merged first, #594 had a mechanical overlap in ISharpLinkClient.cs and SharpLinkClient.CallOptions.cs; the branch now incorporates dev@d03ef7ed0ab3f9171178f8fde0c2b36ba1b6efd5 while preserving both runtime timeout and runtime retry generation semantics. The PR is mergeable again and its final diff remains limited to the 9 retry-related files. Fresh PR Fast/CodeQL checks are running on the resolved head d304cdf0be3cf1a618bad50eea68f04aa5a04779. Repository auto-merge is disabled, so this issue remains open until the gated merge completes.

  2. SunSi12138 commented on Sep 7, 2026

    @SunSi12138
    OwnerAuthor

    PR #594 has passed the required CI checks and was squash-merged into dev.

    Merge commit: fd8832ce7c4b66dee21b2e14ffb7400f4ebab21a

    Runtime retry-policy generation updates are now integrated; closing this issue as completed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions