Skip to content

Session affinity retention on transient errors: port blocked by pinned release-on-failure semantics #204

Description

@warelik

Upstream PR router-for-me/CLIProxyAPI#5109 changes session affinity from "purge the binding on any failure and permanently rebind" to "retain the primary binding across transient failures, use a sticky temporary fallback during the primary's cooldown, and purge/rebind only on terminal auth errors (401/402/403/404, revoked OAuth grant, unsupported model)".

An additive port to this tree is not possible: the behavior change contradicts existing tests that pin the current semantics. Concretely, these existing tests assert the old behavior and would fail under the upstream retention rules:

  • sdk/cliproxy/auth/session_affinity_fix_test.go:74 — asserts HTTP 429 invalidates the binding from the session cache:
    expected cacheKey %q to be invalidated on 429 failure, but still bound to %q
  • the stream-failure variant in the same file — asserts a stream failure invalidates affinity (stream failure should invalidate affinity; still bound=%q)
  • the reselect-after-failure test in selector_test.go — asserts Pick() rebinds to a different auth after a rate_limited failure release
  • TestManagerSessionAffinityPreservesBindingAcrossHigherPriorityRecovery — asserts the failover binding stays after the higher-priority auth recovers (upstream retention instead returns the session to the recovered original)

Those tests encode deliberate Plus-side behavior (see the sibling-scoping work in #188), so flipping them is a product decision, not a mechanical port.

What upstream adds (worth having here if the semantics flip is accepted)

  • isTerminalSessionAffinityError classification: transient errors (429/5xx, overload) retain the binding; only terminal errors release it.
  • A dedicated fallbackCache *SessionCache on SessionAffinitySelector: while the primary is cooling down, the session sticks to one temporary fallback auth (shared across session alias keys) instead of re-drawing a random one per request; when the primary recovers and succeeds, the fallback binding is invalidated and the session returns to the primary.
  • SessionCache.Aliases(sessionID) accessor.
  • Full test suite to port: sdk/cliproxy/auth/session_affinity_retention_test.go (14 cases: transient 503 retention, 429 retry-after retention, terminal 401 unbind, sticky fallback across aliases, model-variant suffix collision safety).

Options

  1. Accept the semantic flip: port the mechanism and update the four pinned tests to the retention expectations (upstream commit 5a4f2086 shows the exact test adjustments).
  2. Keep current Plus semantics and skip the port.
  3. Keep current semantics but add only the sticky temporary fallback (no retention on transient errors) — partially reduces failover flapping without touching the pinned tests.

Cross-link: router-for-me/CLIProxyAPI#5109, related Plus work #188.

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