Skip to content

Dev-runner SIGTERM leaves Vite and backend watchers alive #18625

Closed as not planned

Description

@realhasanshoaib

What happens

Sending SIGTERM to the tracked dev-runner PID leaves its web server and Node watch/server descendants alive. They keep CPU/RAM, file watchers and the original ports. The next runner selects shifted ports instead of reclaiming the stopped instance.

Proof

Reproduced on an isolated macOS M4 checkout at 58d253231d83f669a2cdfefa5fe479751d22c582, with Node 24.13.1:

  1. Start node scripts/dev-runner.ts dev --home-dir <isolated-home> in the background and retain $!.
  2. Confirm that PID is the dev-runner, then send only that PID SIGTERM.
  3. After it exits, the original backend and Vite ports still have listeners. Their lsof -d cwd points into the isolated checkout. Vite has been reparented to PID 1; the backend's Node watch parent also survives.
  4. A second invocation logs server/web offsets of 1 instead of 0. Its separate PATH setup error is unrelated to the surviving listeners.

The observed ports were 13773 and 5733; the next selection was 13774 and 5734. No installed app, user server or agent was stopped.

The spawn intentionally uses detached: false so terminal Ctrl+C reaches the group. That does not give a caller stopping only the tracked runner PID equivalent process-tree cleanup.

Proposed fix

Make runner shutdown terminate its owned child process group, including Node watch and Vite, without matching process names or touching another worktree. Preserve terminal Ctrl+C behavior. Add a subprocess regression that sends SIGTERM to the runner PID and asserts the owned ports close and all captured child PIDs exit; cover normal exit and early spawn failure too.

This is a developer-process lifetime bug, distinct from desktop backend owner-loss issue #13747. It is not claimed as the cause of this user's installed desktop lag.

Found by GPT-6.1-Sol (high), Codex harness in T3 Code.

Activity

  1. juliusmarminge commented on Oct 12, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Thanks for the detailed repro. We're closing this with a workaround rather than tracking it as a bug.

    scripts/dev-runner.ts is a local dev tool meant to run in a terminal. The vp child is spawned with detached: false on purpose (see the comment around L812–815 on main), so it stays in the terminal's process group and Ctrl+C reaches the whole tree directly. The runner doesn't forward signals itself. When it gets a SIGTERM, Effect interrupts the runner and stops only the direct vp child, so grandchildren like Vite and the Node watchers aren't guaranteed to stop. Sending SIGTERM to just the runner PID from a background job isn't a supported way to stop it.

    Workarounds:

    • In a terminal, use Ctrl+C.
    • If you start it in the background, signal the whole process group instead of the PID: kill -TERM -- -<PGID> (ps -o pgid= -p <runner-pid>). Or start it with setsid so it gets its own group you can kill.
    • Leftover instances don't block anything, because the next run moves to free ports. Kill the old group whenever you want those ports back.

    If a supervisor-style workflow (agents or scripts that track one PID) becomes something we support, we can reopen this as an enhancement for the runner to tear down its own process tree on SIGTERM while keeping Ctrl+C behavior the same. This is unrelated to #13747.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requestedvia-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions