1jehuang / 1jehuang/jcode

Windows: bg cancel reports success while npm/cmd/Vitest descendants remain running

Open
#1,081 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

autonomous: no bug triage: needs-decision
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

  1. Start a real watch task through the Bash tool:

    command: npm run test:watch -- --watch tests/unit/storeQuotaV2Display.test.js
    run_in_background: true
    
  2. Wait until Vitest has completed its initial run and is watching:

    Tests 3 passed (3)
    PASS Waiting for file changes...
    
  3. Let the Swarm worker finish.

  4. Confirm with bg status that the task is still running.

  5. Cancel it:

    action: cancel
    graceful_timeout_ms: 5000
    
  6. 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 ...
    
  7. 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 cancel returns success.
  • The task status is persisted as cancelled/failed.
  • npm, cmd, and Vitest descendants remain alive.

Expected behavior

  • bg cancel terminates 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:

  1. Start a live background task that creates a nested Windows process tree.
  2. Call BackgroundTaskManager::cancel_with_grace while the task is still in the in-memory task map.
  3. Assert within a bounded timeout that both the root and descendant processes have exited.
  4. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.