fix(desktop): solve #5699 — retry transient terminal-create network failures

Draft
GI
4mo ago
+185-7

Root cause

The terminal-create path (useV2TerminalLauncher.create) calls
trpcClient.terminal.createSession.mutate(...) directly. That vanilla tRPC
mutation has no retry (React Query's retry config only covers queries), so a
single transient connection-level failure — the local host-service momentarily
unreachable because it's busy under load, mid-restart, or its dynamic loopback
port just rotated — rejects with TypeError: Failed to fetch. useV2PresetExecution
catches it and shows the reported toast:

Failed to run preset — Failed to fetch (127.0.0.1:48135)

This matches the report: it happens after extended usage, is intermittent, and
"resolved by restarting" (which respawns host-service on a fresh port). The
request never reaches host-service, so nothing actually ran.

The fix

terminal.createSession is documented and implemented as idempotent on
host-service (existing in-memory session → no-op; adopt a surviving daemon PTY;
otherwise spawn). Because a connection-level fetch failure never lands on the
server, retrying it can't create a duplicate session. The new
withNetworkRetry helper wraps the create call and retries only transient
network errors (Failed to fetch / Load failed / ECONNREFUSED / …) with a
short linear backoff. Server-side errors (validation, INTERNAL_SERVER_ERROR)
still fail fast.

Tests

create-session-retry.test.ts:

  • Reproduction — with no retry (attempts: 1), a single Failed to fetch
    aborts the call, exactly as the code behaves today.
  • Resolution — a transient failure followed by success now recovers.
  • Guards: gives up after exhausting attempts; never retries non-network errors;
    isTransientNetworkError classification.

Notes / scope

This hardens the renderer→host-service create path, which directly produces the
reported symptom. The underlying flakiness may have additional contributors in
the host-service/daemon lifecycle (e.g. adopted-daemon liveness, port rotation
windows) that are environment-dependent and not deterministically reproducible
in a unit test — hence draft, so a maintainer can confirm this addresses the
field reports before merge.

Closes #5699


Open in Stage

Summary by cubic

Retries transient network failures when creating terminal sessions to prevent the “Failed to run preset — Failed to fetch (127.0.0.1:)” toast. Improves reliability of preset runs and new terminal actions, addressing #5699.

  • Bug Fixes
    • Added withNetworkRetry with short linear backoff; retries only transient network errors (e.g., “Failed to fetch”, “Load failed”, ECONNREFUSED); server errors fail fast.
    • Wrapped trpcClient.terminal.createSession.mutate in useV2TerminalLauncher with the retry helper; safe due to idempotent create semantics.
    • Tests cover reproduction without retry, recovery after a transient blip, giving up after attempts, and error classification.