Skip to content

feat(remote): exponential reconnect backoff + classified disconnect reason - #58

Closed
brettchien wants to merge 1 commit into
fix/remote-session-graceful-teardownfrom
feat/remote-reconnect-backoff-and-error-classification
Closed

feat(remote): exponential reconnect backoff + classified disconnect reason#58
brettchien wants to merge 1 commit into
fix/remote-session-graceful-teardownfrom
feat/remote-reconnect-backoff-and-error-classification

Conversation

@brettchien

Copy link
Copy Markdown
Contributor

Studio-review item 2 (reconnect backoff + error classification) and 斷線原因可觀測性, plus the testable slice of item 3.

Stacked on #57 (fix/remote-session-graceful-teardown) — both touch run_reconnecting. Base is #57's branch; will retarget to main once #57 merges.

What

Before: the reconnect loop retried on a flat 5s cadence, forever, and surfaced every failure as a raw error string. With the gateway's small session-slot pool, a flapping link hammered it on a fixed beat, and the operator couldn't tell a network blip from an auth reject or the server being at capacity.

Changes

  • acp-tunnel — new pure reconnect module (unit-tested, compiles/tests without GTK so it's covered by the workspace CI gate):
    • backoff_delay(attempt, salt) — exponential 1→2→4→8→16s, capped at 30s, with per-connection jitter (salt = first byte of the connection id).
    • DisconnectReason::classify(&str) + label() — buckets an error into network / auth rejected / server at capacity / protocol / other.
  • remote.rs run_reconnecting — escalate backoff on consecutive fast failures; reset to 1s once a connection held ≥15s (a real drop retries fast, a bad dial keeps backing off); put the classified reason in the status line (error: server at capacity, …) + the Activity log. The console already renders the status string, so the reason shows up with no frontend change.

Tests / verification

  • 3 new unit tests (classification of the real DNS-storm string, backoff shape/cap, jitter bound) — run locally, green (cargo test -p acp-tunnel). Session state-machine transitions were already covered in acp-tunnel.
  • cargo check -p acp-tunnel clean. remote.rs compiles under bundle-macos CI (this box has no GTK).

Not in this PR (from the review)

  • Sidecar auto-restart (mcp.rs has no respawn on core crash) — separate PR.

🤖 Generated with Claude Code

…eason

The reconnect loop retried on a flat 5s cadence forever and surfaced every
failure as a raw error blob. With the gateway's handful of session slots, a
flapping link hammered it on a fixed beat, and the operator couldn't tell a
network blip from an auth reject or the server being at capacity.

- acp-tunnel: new pure `reconnect` module (unit-tested, no GTK needed):
  - `backoff_delay(attempt, salt)` — exponential 1→2→4→8→16s capped at 30s
    with per-connection jitter.
  - `DisconnectReason::classify(&str)` + `label()` — network / auth rejected
    / server at capacity / protocol / other.
- remote.rs run_reconnecting: escalate backoff on consecutive fast failures,
  reset once a connection has held ≥15s, and put the classified reason in the
  status line (e.g. "error: server at capacity") + log.

Tests: 3 new reconnect unit tests (classification + backoff shape/cap/jitter);
the Session state machine is already covered in acp-tunnel. The pure policy now
lives in the workspace-tested crate so the Tauri driver stays thin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@brettchien
brettchien deleted the branch fix/remote-session-graceful-teardown August 15, 2026 08:19
@brettchien brettchien closed this Aug 15, 2026
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