Repository navigation
fix(tui): keep long-pending requests past Bun's fetch deadline - #55149
Conversation
|
The following comment was made by an LLM, it may be inaccurate: |
There was a problem hiding this comment.
This fixes the problem. I ran the #54974 reproduction (a plugin /hang command that stays pending, simulated model) from source on the base and on this branch.
- Base: by t+380s the TUI had dropped the request, returned to the home screen and put
/hangback in the composer, while the plugin'sexecutewas still running. - This branch: the TUI stayed on the session past t+400s, and the command finished cleanly once released (~380s).
The packages/tui test passes and its typecheck is clean. The wrapper matches the one in packages/cli/src/run/run.ts, and it covers both places the TUI builds its client (startup and reconnect).
Public API: unchanged.
One point: the added test can be dropped (see the inline comment).
Related: #50135
| @@ -0,0 +1,37 @@ | |||
| import { expect, test } from "bun:test" | |||
There was a problem hiding this comment.
This test can be dropped so the change stays minimal. It replaces globalThis.fetch only to check a one-line spread. It doesn't show that the TUI client actually uses the wrapper, or that a request survives past Bun's deadline.
BrickerP
left a comment
There was a problem hiding this comment.
Verdict: would APPROVE (posted as COMMENT — no write access for formal approve)
Mirrors the existing CLI workaround in packages/cli/src/run/run.ts (fetch(request, { ...init, timeout: false } as BunFetchRequestInit) and wires it into both TUI OpenCode.make sites in packages/tui/src/app.tsx (startup options ~L215 and reconnect next ~L229). That is the right place for #54974’s transport drop: Bun’s ~5 min deadline, not a server limit.
Verified
- Wrapper
{ ...init, timeout: false }preservessignal/ otherRequestInitfields; only Bun’s fetch deadline is disabled — same hang-vs-abort tradeoff the CLI already accepted. - Both construction paths covered; reconnect cannot fall back to a default-deadline client.
- Unit test checks
timeout: falseforwarding with and withoutinit; type cast toBunFetchRequestInitmatchesrun.ts. - Scope correctly leaves Promise-executor cancellation to #53913 / #53914.
Non-blocking
packages/cli/src/mini.tscreateMiniConnectionstill builds a plainOpenCode.make(notimeout: false) — same shape as #50135; out of scope here but still a stock-client gap.- Optional later: share one helper between CLI and TUI instead of duplicating the one-liner.
CI on head 0e6a6ba: check-duplicates / check-standards / check-compliance all success.
|
Addressed in 7822a90: the wrapper test is dropped so the diff stays minimal -- it only pinned the one-line spread. The change is now just |
The TUI client inherits Bun's default five-minute fetch deadline, so a plugin command whose execute stays pending is dropped client-side (server logs 499) while the executor keeps running. The run entry point already opts out for long-lived requests; give the TUI client the same treatment at both construction sites (initial and service reconnect).
The test only pinned a one-line spread and did not show the TUI client actually uses the wrapper; removing it keeps the change minimal.
Move the Bun fetch timeout opt-out into @opencode/util/no-timeout-fetch and use it from run, mini and the TUI. Existing-session shell commands now toast and restore the composer on failure, matching the command path.
7822a90 to
fc9891f
Compare
|
Thanks @Finn763, this is merged as 52a10f5. Your fix, plus the clear reproduction in the issue, made this easy to land. Before merging, I rebased it onto the latest
Cancelling plugin executors is still out of scope here and stays with #53913 / #53914. — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊 |
…lyco#55149) Give the TUI client timeout: false, share the no-timeout fetch helper across run, mini and the TUI via @opencode/util/no-timeout-fetch, and surface existing-session shell failures with a toast and composer restore. Closes anomalyco#54974 Co-authored-by: Finn763 <finn763@users.noreply.github.com> (cherry picked from commit 52a10f5)
* docs: plan transport and lifecycle backport Implement the assigned transport and lifecycle behavior in existing fork owners. - Pick each donor in its own -x commit; omit shell-failure UI and absent CLI/MCP payload. - Disable Bun’s independent fetch deadline only for long network clients and native provider requests; preserve caller signals, domain deadlines, and the #303 watchdog. - Track detached POSIX groups only while cleanup is owed, preserving #380 escalation and release of intentional descendants; route terminal SIGHUP through the TUI lifecycle. - Add real-server and child-process regressions with removal proofs, then record donor coverage and focused checks in CHANGESET.md. * fix(tui): keep long-pending requests past Bun's fetch deadline (anomalyco#55149) Give the TUI client timeout: false, share the no-timeout fetch helper across run, mini and the TUI via @opencode/util/no-timeout-fetch, and surface existing-session shell failures with a toast and composer restore. Closes anomalyco#54974 Co-authored-by: Finn763 <finn763@users.noreply.github.com> (cherry picked from commit 52a10f5) * fix(core): disable Bun's fetch idle timeout for provider requests (anomalyco#55007) (cherry picked from commit 460c626) * fix(util): kill spawned process groups when opencode exits (anomalyco#59411) (cherry picked from commit e2bc79d) * fix(core): type Bun fetch timeout overrides * test(opencode): verify mini attach timeout wiring Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(core): verify abrupt owner process-group cleanup Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(tui): verify SDK long-call fetch policy Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * fix(tui): preserve nohup SIGHUP behavior Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(core): verify native fetch timeout override Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(core): prove native requests outlive default idle timeout Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(opencode): verify attached runs survive Bun idle timeout Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * docs: record transport and lifecycle backport Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * docs: clarify backport regression ownership Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(opencode): allow Bun 1.4.4 server startup window Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test: shorten idle-timeout acceptance tests Run the native and attached held-response witnesses in bounded Bun 1.4.4 child processes with BUN_CONFIG_HTTP_IDLE_TIMEOUT=2 so they stay out of the multi-minute range. Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(tui): prove SDK long calls survive Bun idle expiry Exercise SDKProvider's external SDK and SSE paths with a held event stream, a real timeout control, and a completed event after the injected short idle expiry. Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(opencode): prove mini attach survives Bun idle expiry Hold the real mini attach session response in a Bun 1.4.4 child process, observe an unmodified control fetch time out first, then release the expected 404 response. Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * test(tui): make SIGHUP fixture reports truthful Keep the nohup fixture scoped to listener policy and process survival, and add a non-TTY non-nohup default-disposition witness while retaining lifecycle assertions only from the real TUI producer. Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * fix(tui): clean Worker-owned process groups on exit Acknowledge Worker group ownership and release events, kill and await remaining groups before the shutdown reply, and use the recorded PGID ledger as the bounded TUI-owner backstop when shutdown is unconfirmed. Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * docs: finalize transport exit review coverage Record the acknowledged TUI Worker group lifecycle, truthful SIGHUP behavior, and short Bun 1.4.4 behavioral witnesses in the backport ledger. Claude-Session: c368ed23-1e31-4f2c-b305-b84f21d79cc5 * fix(tui): centralize Worker process-group ownership * docs: plan transport exit review fixes 1. Make worker and parent ownership ledgers converge on each local acquire, release, and cleanup decision even when acknowledgement is rejected or delayed; validate recorded identities before parent-side signalling. 2. Add rejected/delayed acknowledgement regressions for acquire, release, cleanup announcement, and release/reacquire identity fallback. 3. Harden fixture cleanup and deadlines; add Linux-only guards; correct CHANGESET ownership and SIGHUP claims; remove only test hooks no longer needed. 4. Verify focused changed cases and then each importing test file once under checksum-verified Bun 1.4.4; commit without pushing. * fix(core): reconcile process-group acknowledgement failures Reconcile Worker and parent ownership ledgers on local acquire, release, and cleanup facts, independent of rejected or delayed acknowledgements. Validate recorded member identities before signalling and preserve released member identities across reacquisition. Bound identity-owned process fixture cleanup, gate procfs child fixtures to Linux, retain portable SDK cancellation coverage, and correct the #410 SIGHUP and ownership ledger. Claude-Session: unknown * test(opencode): gate shell output on spawn readiness Wait for the process spawn acknowledgement before the ShellTool first-output deadline and reap the child on readiness failure. Tighten process-group fixture types for package typecheck. Claude-Session: unknown * fix(core): restore cross-platform process group cleanup Claude-Session: unavailable (OpenCode session) * fix(core): unify process-group ownership decisions Claude-Session: unavailable (OpenCode session) * fix(core): publish process-group ownership updates Claude-Session: unavailable (OpenCode session) * test(opencode): cover cancellation-overlap ownership Claude-Session: unavailable (OpenCode session) * test(core): wait for process-group cleanup Claude-Session: unavailable (OpenCode session) * test(opencode): harden process-group test results Claude-Session: unavailable (OpenCode session) * test(opencode): validate cancellation result shape Claude-Session: unavailable (OpenCode session) * test(opencode): type fixture results as unknown Claude-Session: unavailable (OpenCode session) --------- Co-authored-by: Finn763 <165816600+Finn763@users.noreply.github.com> Co-authored-by: Finn763 <finn763@users.noreply.github.com> Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>


Issue for this PR
Closes #54974
Type of change
What does this PR do?
The TUI builds its client with plain
OpenCode.make(...), so its requests inherit Bun's default five-minute fetch deadline. A plugin command whoseexecutestays pending (or a longsession.shellcall) is accepted by the server, but the client transport drops the request at ~5-6 min — the server logs499, the UI restores the composer and navigates away, and the executor keeps running.This PR gives the TUI client
timeout: falseat both construction sites (the initial client and the service reconnect path), matching whatrunandminialready do.Maintainer follow-ups folded in:
fetch(request, { ...init, timeout: false })wrapper lived inpackages/cli/src/run/run.tsandpackages/cli/src/mini.ts, and would have been a third copy here. It now lives once in@opencode/util/no-timeout-fetch(bothcliandtuialready depend on@opencode/util) and is used by run, mini and the TUI.session.shellwas fired with no.catch, so a rejected shell command became an unhandled rejection with no feedback. It now uses the samefail(...)toast + composer restore as thesession.commandpath (new sessions still go throughnewSession.recover).Scope note: Promise executors still keep running with no cancellation signal; that belongs with the command lifetime/cancellation work (#53913 / #53914).
How did you verify your code works?
packages/util/src/no-timeout-fetch.test.ts: the helper preserves method/headers/body and still honours an abortsignal.packages/tui/test/prompt-shell-failure.test.tsx: a failingsession.shellin an existing session shows "Failed to run shell command" and restores the composer (fails with an unhandledShell unavailableerror without the fix; 20/20 with--rerun-each).packages/cli/test/mini-timeout.test.ts(withBUN_CONFIG_HTTP_IDLE_TIMEOUT=1) still passes through the shared helper.bun run checkclean.Checklist