[GH-ISSUE #4258] [Bug] Windows exclusive runner records cancellation without stopping its owned command #1683

Closed
opened 2026-10-16 21:09:01 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @morluto on GitHub (Oct 15, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4258

Before submitting

  • Searched open and closed issues for Windows/run-exclusive cancellation reports.
  • Uses disposable owned fixtures; no credentials or target data.

Area / interface / failure stage

Other: development command runner / Other / Cleanup, cancellation, or lifecycle.

Observed behavior

Source-derived Windows finding, with a controlled branch experiment on macOS. Real Windows execution is NOT_ENOUGH_INFO. The exclusive-command supervisor records IPC cancellation or parent disconnection on Windows but does not terminate its directly owned command. It waits for the command's close event while retaining the SQLite transaction. A hung command can therefore retain the exclusive lock after the parent has requested shutdown.

Reproduction actually run

On an isolated source copy, force the existing Windows branch and run a disposable Node child whose exit is gated by a temporary file. Forward SIGTERM over the supervisor's IPC channel and observe receipt. The supervisor and command stay alive until the file gate opens; then the supervisor exits 143. The unchanged POSIX control exits 143 when cancellation is forwarded. This tests branch logic, not native Windows signal behavior or a Windows SQLite contender.

Expected behavior / impact and scope

Cancellation and parent disconnection should stop the directly owned command, observe its exit, then release the lock. Source-derived impact is a retained command and lock when the command does not exit itself. Native Windows frequency and descendant behavior remain NOT_ENOUGH_INFO. Existing POSIX cancellation coverage skips Windows.

REA version / runtime / target

Source 0e1f0bf2d06943e59253b8a66923a1ae6005e81e; Node 24.18.0, macOS arm64. Disposable gated Node command. Windows runtime coverage unavailable on this host.

Relevant evidence

Proposed repair and verification

Terminate through the already-owned ChildProcess handle and retain the transaction until observed child exit. Do not use an unverified PID or process-tree kill. Add native Windows regressions for IPC-forwarded cancellation and parent disconnection, checking command exit before a contender can acquire the lock. Parent audit: #4227.

Originally created by @morluto on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4258 ## Before submitting - [x] Searched open and closed issues for Windows/run-exclusive cancellation reports. - [x] Uses disposable owned fixtures; no credentials or target data. ## Area / interface / failure stage Other: development command runner / Other / Cleanup, cancellation, or lifecycle. ## Observed behavior **Source-derived Windows finding, with a controlled branch experiment on macOS. Real Windows execution is NOT_ENOUGH_INFO.** The exclusive-command supervisor records IPC cancellation or parent disconnection on Windows but does not terminate its directly owned command. It waits for the command's `close` event while retaining the SQLite transaction. A hung command can therefore retain the exclusive lock after the parent has requested shutdown. ## Reproduction actually run On an isolated source copy, force the existing Windows branch and run a disposable Node child whose exit is gated by a temporary file. Forward SIGTERM over the supervisor's IPC channel and observe receipt. The supervisor and command stay alive until the file gate opens; then the supervisor exits 143. The unchanged POSIX control exits 143 when cancellation is forwarded. This tests branch logic, not native Windows signal behavior or a Windows SQLite contender. ## Expected behavior / impact and scope Cancellation and parent disconnection should stop the directly owned command, observe its exit, then release the lock. Source-derived impact is a retained command and lock when the command does not exit itself. Native Windows frequency and descendant behavior remain NOT_ENOUGH_INFO. Existing POSIX cancellation coverage skips Windows. ## REA version / runtime / target Source `0e1f0bf2d06943e59253b8a66923a1ae6005e81e`; Node 24.18.0, macOS arm64. Disposable gated Node command. Windows runtime coverage unavailable on this host. ## Relevant evidence - [Supervisor signal handler](https://github.com/morluto/rea/blob/0e1f0bf2d06943e59253b8a66923a1ae6005e81e/scripts/run-exclusive-command.mjs#L99): records shutdown, then returns immediately on `win32`. - [Command wait and lock lifetime](https://github.com/morluto/rea/blob/0e1f0bf2d06943e59253b8a66923a1ae6005e81e/scripts/run-exclusive-command.mjs#L57): `run()` awaits `runCommand()` before closing the database; command completion waits for `close`. - [Existing cancellation tests](https://github.com/morluto/rea/blob/0e1f0bf2d06943e59253b8a66923a1ae6005e81e/tests/process-global/runnerCancellation.test.ts) are POSIX-only. - Official Node 24 docs distinguish [child termination through its handle](https://nodejs.org/docs/latest-v24.x/api/child_process.html#subprocesskillsignal) from [IPC disconnection](https://nodejs.org/docs/latest-v24.x/api/child_process.html#subprocessdisconnect). ## Proposed repair and verification Terminate through the already-owned `ChildProcess` handle and retain the transaction until observed child exit. Do not use an unverified PID or process-tree kill. Add native Windows regressions for IPC-forwarded cancellation and parent disconnection, checking command exit before a contender can acquire the lock. Parent audit: #4227.
bsakaguchi 2026-10-16 21:09:01 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

@morluto commented on GitHub (Oct 16, 2026):

Fixed on main in c7b70896b. Windows cancellation and parent disconnection now stop the directly owned ChildProcess; the exclusive transaction remains held until observed child close.

Windows-gated IPC cancellation/disconnect regressions were added. Native Windows execution remains unverified; this closure addresses the documented source omission without claiming host qualification.

Hosted main CI is still pending; this closure is based on the implemented fix and the scoped regression evidence.

<!-- gh-comment-id:6206010877 --> @morluto commented on GitHub (Oct 16, 2026): Fixed on `main` in [c7b70896b](https://github.com/morluto/rea/commit/c7b70896b1a1f346f1dc591773e776444a8f5f98). Windows cancellation and parent disconnection now stop the directly owned ChildProcess; the exclusive transaction remains held until observed child close. Windows-gated IPC cancellation/disconnect regressions were added. Native Windows execution remains unverified; this closure addresses the documented source omission without claiming host qualification. Hosted main CI is still pending; this closure is based on the implemented fix and the scoped regression evidence.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#1683
No description provided.