[PR #13848] fix(tui): add signal handlers to prevent orphaned processes on terminal close #14841

Open
opened 2026-02-16 18:19:35 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/13848

State: open
Merged: No


What does this PR do?

Fixes #12767, relates to #11527, #10563

When a terminal tab is closed, @opentui/core's exitHandler catches SIGTERM/SIGINT/SIGQUIT/SIGABRT but only calls destroy() without calling process.exit() or re-raising the signal -- silently swallowing them. SIGHUP has no handler at all. The Worker thread keeps the event loop alive, so the bun binary survives as an orphan (PPID=1) with revoked file descriptors, leaking memory indefinitely.

On my machine this accumulated 152 orphaned processes over 10 days.

b1affa4d177d89e62b7fbfcccc0248ca 52c4ac4bf5515ac18ef0b3781a2a5c65

The fix adds signal handlers in thread.ts that gracefully shut down the worker (disposes instances, stops servers) before calling process.exit() with the correct exit code (128 + signum). A 5s timeout ensures exit even if shutdown hangs. A reentrancy guard prevents double-shutdown from multiple signals.

How did you verify your code works?

  • tsc --noEmit passes (0 errors in opencode package)
  • Verified SIGHUP/SIGTERM kill orphaned processes: kill -HUP <pid> and kill -TERM <pid> both cause clean exit
  • Confirmed normal Ctrl+C / Ctrl+D exit path is unaffected (raw mode means SIGINT is not generated by the terminal driver; the app handles ^C as a keypress)
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/13848 **State:** open **Merged:** No --- ### What does this PR do? Fixes #12767, relates to #11527, #10563 When a terminal tab is closed, `@opentui/core`'s `exitHandler` catches SIGTERM/SIGINT/SIGQUIT/SIGABRT but only calls `destroy()` without calling `process.exit()` or re-raising the signal -- silently swallowing them. SIGHUP has no handler at all. The Worker thread keeps the event loop alive, so the bun binary survives as an orphan (PPID=1) with revoked file descriptors, leaking memory indefinitely. On my machine this accumulated **152 orphaned processes** over 10 days. <img width="391" height="259" alt="b1affa4d177d89e62b7fbfcccc0248ca" src="https://github.com/user-attachments/assets/af2a0370-1571-4720-81fc-ca422644f15e" /> <img width="690" height="815" alt="52c4ac4bf5515ac18ef0b3781a2a5c65" src="https://github.com/user-attachments/assets/e4843edd-637e-4111-a77c-adcb155982fb" /> The fix adds signal handlers in `thread.ts` that gracefully shut down the worker (disposes instances, stops servers) before calling `process.exit()` with the correct exit code (128 + signum). A 5s timeout ensures exit even if shutdown hangs. A reentrancy guard prevents double-shutdown from multiple signals. ### How did you verify your code works? - `tsc --noEmit` passes (0 errors in `opencode` package) - Verified SIGHUP/SIGTERM kill orphaned processes: `kill -HUP <pid>` and `kill -TERM <pid>` both cause clean exit - Confirmed normal Ctrl+C / Ctrl+D exit path is unaffected (raw mode means SIGINT is not generated by the terminal driver; the app handles `^C` as a keypress)
yindo added the pull-request label 2026-02-16 18:19:35 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#14841