Skip to content

On Windows, stopping a check can leave its processes running #490

Closed

Description

@Sequela02

Found while landing the gate's move to Effect (#487).

What happens

On Windows CI, stopping a run while the gate runs a project's check leaves the check's processes running: a test's node long.cjs and the child it started were both alive 10 s after the stop, and would run their full minute. On the owner's machine the same test passes.

Cause, from a diagnostic on CI

The chain of parents of the check's node, taken before the stop, already hangs off a process that no longer exists:

node long.cjs <- cmd.exe /d /s /c node long.cjs <- node (npm) <- usr\bin\bash.exe (npm's script) <- usr\bin\bash.exe <- 4428 (gone)

Git's bash on CI replaces itself with the last command it runs (exec), which MSYS does by starting a new Windows process and letting the old one exit. That breaks the Windows parent chain, so taskkill /F /T /PID <pid>, which stopTree (src/process.ts) runs on the process runProcess started, no longer reaches npm, node and their children. On the owner's machine the chain goes through sh.exe and stays whole, so the stop closes everything.

This predates Effect: stopTree has always started from the process it spawned and followed the parent chain. Nothing checked that a stopped check's processes were gone on Windows CI until #487's test.

Effect

On Windows setups where bash execs, stopping a run, or a check running past its time limit, can leave the check's processes (a test runner, a dev server, Dafny) running after Tesota reports.

Fix to consider

A Windows Job Object: runProcess creates a job, assigns the process it starts to it, and stopping terminates the job, which ends every descendant however the parent chain looks (CreateJobObjectW, AssignProcessToJobObject, TerminateJobObject, through bun:ffi as session-lock.ts already uses kernel32; or kill-on-close). Check that MSYS processes stay in the job rather than breaking away.

Acceptance

  • The test in packages/core/tests/gate.test.ts, "the operator's stop while a check runs…", checks that the check's processes are gone on Windows too: remove its Windows exception, marked temporary until this issue.
  • It passes on Windows CI.

Activity

  1. Sequela02 commented on Oct 18, 2026

    @Sequela02
    ContributorAuthor

    Fixed in #492: on Windows under Bun each process runProcess starts goes into a Job Object, which a stop or time limit terminates, so its descendants end however their parents come and go. Both process tests pass on Windows CI.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions