Skip to content

fix: force-kill the captured PET child so restart cannot lose or misfire the kill - #19

Open
StellaHuang95 wants to merge 2 commits into
mainfrom
fix-pet-force-kill
Open

fix: force-kill the captured PET child so restart cannot lose or misfire the kill#19
StellaHuang95 wants to merge 2 commits into
mainfrom
fix-pet-force-kill

Conversation

@StellaHuang95

Copy link
Copy Markdown
Owner

Fixes a force-kill ownership bug in the PET (python-environment-tools) child-process teardown in src/managers/common/nativePythonFinder.ts.

Problem

PET runs as a long-lived child process managed by NativePythonFinderImpl. When a request times out or the RPC connection breaks, recovery calls killProcess() to terminate the hung child, then restart() spawns a fresh one into this.proc. The teardown could act on the wrong process across that restart boundary.

Root cause

killProcess() sent SIGTERM, scheduled a 500 ms setTimeout that re-read the mutable this.proc field to decide whether to SIGKILL, then synchronously set this.proc = undefined. When the callback ran, this.proc was either already undefined (so a hung PET was never SIGKILLed) or had been reassigned by a concurrent restart (so the callback could SIGKILL the healthy replacement).

Fix

Extract killPetProcessWithGrace(getProc, clearProc, outputChannel, graceMs), which captures the current child and clears the holder before signalling, then sends SIGTERM and — after the grace period — SIGKILLs only that captured child. killProcess() delegates via () => this.proc / () => { this.proc = undefined; }. Because the delayed SIGKILL closes over the captured local child rather than the mutable field, a concurrent restart's replacement is never targeted, and a hung child is reliably force-killed. The grace period is unchanged (KILL_PROCESS_GRACE_PERIOD_MS = 500). No PET source is touched and there is no extension-API change.

Tests

nativePythonFinder.killProcess.unit.test.ts (6 cases, sinon fake timers): SIGTERMSIGKILL on the captured child, synchronous ownership release, exit-during-grace not force-killed, already-exited child not signalled (holder still cleared), a replacement assigned during the grace period is never killed (key regression), and SIGTERM errors are caught/logged without throwing. All 6 pass; npm run lint and npm run compile-tests are clean.

…ire the kill

killProcess() sent SIGTERM, scheduled a 500ms callback that re-read the
mutable this.proc field, then cleared it synchronously. By the time the
callback ran, this.proc was either already undefined (a hung PET was
never SIGKILLed) or reassigned by a concurrent restart (the delayed
SIGKILL could hit the healthy replacement).

Extract killPetProcessWithGrace, which captures the child and clears the
holder before signalling, so the delayed SIGKILL only ever targets that
captured child. Add focused ownership regression tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@StellaHuang95 StellaHuang95 added the bug Something isn't working label Aug 23, 2026
@StellaHuang95

StellaHuang95 commented Aug 23, 2026

Copy link
Copy Markdown
Owner Author

🔒 Automated review in progress — @StellaHuang95 is auto-reviewing this PR.

Comment thread src/managers/common/nativePythonFinder.ts
@StellaHuang95 StellaHuang95 added the review-auto:changes-requested Automated review: posted blocking findings to address. label Aug 23, 2026
…is not SIGKILLed

A child that responds to SIGTERM reports exitCode === null with signalCode set, so
guarding the escalation on exitCode alone still fired SIGKILL at an already-terminated
child. Include signalCode in KillablePetProcess and only signal while both terminal-state
fields are null; extend the test double with signalCode and cover the SIGTERM-during-grace case.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@StellaHuang95 StellaHuang95 added review-auto:approved Automated review: no blocking findings (approval posted). and removed review-auto:changes-requested Automated review: posted blocking findings to address. labels Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working review-auto:approved Automated review: no blocking findings (approval posted).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant