Windows: bg cancel reports success while npm/cmd/Vitest descendants remain running
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 19.9k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 30
Description
Summary
On Windows, cancelling a live background Bash task through bg cancel reports success and marks the task as cancelled/failed, but the npm/cmd/Vitest descendant process tree can remain alive.
This leaves test watchers consuming CPU, memory, and file handles after the Swarm worker has finished and after Jcode reports the background task as cancelled.
Environment
- Jcode:
v0.80.1 (59aaacc) - OS: Windows x86_64
- Shell:
cmd.exe - Workload: Vitest watch mode launched through npm
Reproduction
-
Start a real watch task through the Bash tool:
command: npm run test:watch -- --watch tests/unit/storeQuotaV2Display.test.js run_in_background: true -
Wait until Vitest has completed its initial run and is watching:
Tests 3 passed (3) PASS Waiting for file changes... -
Let the Swarm worker finish.
-
Confirm with
bg statusthat the task is stillrunning. -
Cancel it:
action: cancel graceful_timeout_ms: 5000 -
Jcode reports that the task was cancelled, but the Windows process tree still contains the npm/cmd/Vitest descendants:
npm run test:watch cmd.exe node.exe ... vitest.mjs --watch ... -
A targeted tree kill is still required to remove them:
taskkill /PID <npm-root-pid> /T /F
The reproduction was cleaned up with a targeted PID tree kill. An unrelated pre-existing Vite/Electron development process was left running and unaffected.
Actual behavior
bg cancelreturns success.- The task status is persisted as cancelled/failed.
- npm, cmd, and Vitest descendants remain alive.
Expected behavior
bg cancelterminates the full process tree owned by the background task.- Jcode confirms the tree has exited before reporting cancellation success.
- If cleanup fails, cancellation should return an error instead of reporting success.
Source analysis
BackgroundTaskManager::cancel_with_grace in crates/jcode-base/src/background.rs has two different paths.
For a task still present in the in-memory task map, it currently calls:
task.handle.abort();
It then immediately writes a terminal status and returns Ok(true). This path does not call signal_detached_process_group, wait for the command to exit, or verify that descendants are gone.
For a detached task, the Windows branch does call:
crate::platform::signal_detached_process_group(pid, 0);
crates/jcode-base/src/platform.rs implements that operation with:
taskkill.exe /PID <pid> /T /F
The existing commit 74f9583f5 (fix(windows): terminate detached process trees) and its regression test cover this detached-process helper, but not the live in-process cancellation branch.
In crates/jcode-app-core/src/tool/bash.rs, Windows background commands rely on kill_on_drop(true). Aborting the Tokio task kills the direct child, but does not guarantee that npm/cmd/test-runner descendants exit.
Related issue
This is related to, but distinct from, #940. That issue concerns detached commands surviving or being replayed after stopping Swarm workers and server reloads. This report reproduces the failure directly through the public bg cancel interface while the task is still managed as a live in-process background task on Windows.
Suggested acceptance coverage
A regression test should exercise the real manager cancellation path:
- Start a live background task that creates a nested Windows process tree.
- Call
BackgroundTaskManager::cancel_with_gracewhile the task is still in the in-memory task map. - Assert within a bounded timeout that both the root and descendant processes have exited.
- Verify cancellation is only reported successful after process-tree cleanup completes.
A Windows Job Object with kill-on-close semantics may also provide stronger lifecycle guarantees than relying only on direct-child termination.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in crates/jcode-base/src/background.rs at BackgroundTaskManager::cancel_with_grace, then compare the live in-process path with signal_detached_process_group in crates/jcode-base/src/platform.rs and the Windows background setup in crates/jcode-app-core/src/tool/bash.rs. Add regression coverage for a nested Windows process tree, verify root and descendants exit within a bounded timeout, and confirm cancellation is reported only after cleanup.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bash, rust
- Domain
- cli, operating-systems, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100