Repository navigation
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
There was a problem hiding this comment.
I found no blocking problems. I pointed createClientConnection at an unreachable server for 20 s on both checkouts. The base retried every ~1 s (20 attempts). This PR backed off 1/2/4/8 s (5 attempts), and a resync during the pause retried immediately. solid-connection.test.ts passes, and the new test fails on the base. tsc --noEmit is clean for packages/client and packages/app.
The public API is unchanged: @opencode/client/solid keeps the same exports and options. Only its retry timing changes, and resync() now also does something while the stream is down.
One thing worth a look (inline): the TUI uses the same connection but never calls resync, so it now gets the longer wait with no early retry.
| continue | ||
| } | ||
| await wait(reconnectDelay, controller.signal) | ||
| pause = new AbortController() |
There was a problem hiding this comment.
The TUI (packages/tui/src/context/client.tsx) uses this loop too, and it has no pageLifecycle or online/visibility events to trigger resync. With an explicit --server and no managed service, a server that is down for a while (for example during an upgrade restart) is now picked up up to ~30 s after it comes back, instead of within ~1 s. Is that intended for the TUI, or should the backoff (or a lower cap) be enabled only where something can call resync?
When a server in the list stops answering, the app retries its event stream every 3 s indefinitely: a 2 s connect timeout plus a 1 s pause. A debug export from a desktop with an offline Tailscale server showed:
[global-sdk] event stream disconnectedlines in 56 min.ERR_CONNECTION_TIMED_OUT.[object Object], so finding which server failed took the netlog.Fix
createClientConnectiondoubles the pause after each attempt that fails before the stream connects: 1, 2, 4, 8, 16, then 30 s. A stream that stays connected for 1 s resets the pause, as before.resyncduring the pause ends it. Coming back online, or returning to a window whose stream went quiet, retries at once.flowchart LR A["attempt fails before server.connected"] --> B{"resync?<br/>online, page visible"} B -- yes --> C["retry now"] B -- no --> D["pause min(1 s × 2^(n-1), 30 s)"] --> C C --> A C -- "connected ≥ 1 s" --> E["attempt = 0"]Unreachable server, 40 min
dev(netlog)Visual
Added by the opencode bot (AI-generated).
Fixes #48014
Related: #53498, #52271, #57807