Skip to content

feat: named RetryCurve API for switching retry regimes at runtime - #68

Draft
tanderson-ld wants to merge 1 commit into
mainfrom
ta/SDK-2788/retry-conformance
Draft

feat: named RetryCurve API for switching retry regimes at runtime#68
tanderson-ld wants to merge 1 commit into
mainfrom
ta/SDK-2788/retry-conformance

Conversation

@tanderson-ld

Copy link
Copy Markdown

Summary

Adds a RetryCurve API so a caller can register multiple retry-timing curves on a single stream and switch between them at runtime via Stream.ActivateCurve. Enables consumers to run a multi-regime retry policy (e.g., a normal regime + an extended regime for auth failures) while keeping the library's single-regime timing path intact for existing callers.

Marked draft for API/design socialization before dependent SDK work builds on it.

API additions

  • NewRetryCurve(options ...RetryCurveOption) *RetryCurve — construct an opaque handle.
  • RetryCurveBaseDelay(d), RetryCurveMaxDelay(d), RetryCurveJitter(r) — curve options.
  • StreamOptionDefaultRetryCurve(curve) — designate as the stream's effective default.
  • StreamOptionRegisterRetryCurve(curve) — register as an additional switchable curve.
  • Stream.ActivateCurve(curve *RetryCurve) — switch the currently-active curve at runtime.
  • DefaultCurve — package-level sentinel meaning "revert to the effective default."
  • MaxServerDirectedRetryDelay = time.Hour — clamp ceiling for the SSE retry: field.

Legacy stream options (StreamOptionInitialRetry, StreamOptionUseBackoff, StreamOptionUseJitter, StreamOptionRetryResetInterval) continue to work unchanged; when no explicit RetryCurve is provided they synthesize the effective default.

Semantics

  • Lazy overlay resolution. At delay-computation time, each property is resolved by walking active-curve.speceffective-default.spec → hard-coded fallback. Curve specs are immutable.
  • Per-curve formula counter n. Each registered curve tracks its own backoff-formula counter. Progression is retained across activations, so rapid oscillation between regimes preserves each regime's state.
  • Healthy-op reset. When elapsed >= resetInterval, zeros every curve's n and reverts active to the effective default. Does NOT clear server-directed base-delay overrides (matches HTML5 SSE spec's "reconnection time is set until updated").
  • Server retry: field. Updates every registered curve's base-delay override (stream-wide per HTML5). Never touches any curve's declared maxDelay ceiling.
  • Wire clamp. SSE retry: values above MaxServerDirectedRetryDelay are clamped, in milliseconds before the time.Millisecond multiplication, so extreme int64 wire values cannot overflow the Duration.

Internal notes for reviewers

  • backoffStrategy.applyBackoff and jitterStrategy.applyJitter interfaces were widened to accept per-call maxDelay / ratio. Math bodies are unchanged from the pre-existing library; only the parameter source moved from receiver fields to method args, so one strategy instance can serve multiple curves.
  • Internal SetBaseDelay renamed to ApplyRetryTime; it now iterates all registered curves.

Test plan

  • Full test suite passes (go test ./...).
  • SSE contract-test harness passes (make contract-tests — "All tests passed").
  • Pre-existing backoff/jitter math bodies preserved byte-for-byte in effect (only parameter sourcing changed).
  • Library-maintainer review.

Refs SDK-2788.

Introduces a RetryCurve opaque handle. Callers construct curves via
NewRetryCurve(options...), designate them at subscribe time via
StreamOptionDefaultRetryCurve / StreamOptionRegisterRetryCurve, and switch
between them at runtime via Stream.ActivateCurve. Enables SDKs to run a
multi-regime retry policy (e.g., a normal regime + an extended regime for
auth failures) while keeping the library's single-regime timing path intact
for legacy callers.

Overlay resolution walks (active-curve spec -> effective-default spec ->
hard-coded fallbacks), evaluated lazily at delay-computation time. Per-curve
formula counter n is retained across activations. Healthy-operation reset
zeros all curves' formula counters and reverts to the effective default; it
does not clear base-delay overrides (matches SSE spec's "reconnection time
is set until updated").

SSE `retry:` field is honored per HTML5 semantics: the stream read loop
updates every registered curve's base-delay override. Values above 1 hour
are clamped per RETRY spec section 1.11.4 (new MaxServerDirectedRetryDelay
constant). Clamping happens in milliseconds before the multiplication by
time.Millisecond so extreme wire values cannot overflow the Duration.

Internal changes:
- Widened backoffStrategy.applyBackoff and jitterStrategy.applyJitter to
  accept per-call maxDelay / ratio so a single strategy instance can serve
  multiple curves. Math bodies unchanged from the pre-existing library.
- Renamed internal SetBaseDelay to ApplyRetryTime; it now iterates all
  registered curves.

Legacy stream options (StreamOptionInitialRetry / UseBackoff / UseJitter /
RetryResetInterval) continue to work unchanged; when no explicit
RetryCurve is provided they synthesize the effective default.

Refs SDK-2788.
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