Plugin shutdown kills only the plugin process, not its children
- Status: Done
- Kind: Bug
- Authors: jp
- Date: 2026-09-28
- Implements: 072
- Label: client=cli
- Label: domain=plugins
- Label: package=jp_cli
- Label: type=bug
When a plugin does not exit within the shutdown grace period, JP kills the process it spawned and nothing else. A subprocess the plugin started survives, keeps any port it bound, and can keep JP from exiting.
Why
- The child is spawned with
process_group(0), so its subprocesses share its group and are also shielded from the terminal's Ctrl-C. kill_child(crates/jp_cli/src/cmd/plugin/dispatch.rs) sendsSIGKILLto the positive PID on Unix, andTerminateProcessto that one process on Windows.- Cleanup then joins the stderr reader thread, which blocks for as long as a surviving descendant holds the inherited stderr pipe open.
Scope
A shell-script plugin that runs a worker in the foreground (a server, a watcher) and then Ctrl-C. The worker outlives jp, and jp itself can hang on exit.
Fix
- Unix: kill the group,
kill(-pid, SIGKILL); the child already leads it. - Windows: assign the child to a Job Object at spawn and terminate the job.
- Bound the stderr join once the group is gone.
RFD 072 states the guarantee: JP owns the plugin's process tree for the invocation, and deliberately detached descendants are unsupported.
Verifying
A shell plugin that starts sleep 600 &-style foreground worker and ignores shutdown: after the grace period, assert the worker's PID no longer exists and jp has exited.