fix(process): release handles and close worker on incomplete cleanup (#2321)

* fix(process): unreference handles on incomplete provider process stop

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>

* fix(javascript): close worker and release handles on incomplete cleanup

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>

* fix(javascript): defer worker stdin close until incomplete cleanup

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>

* test(javascript): assert cleanup error instance on inspection uncertainty

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>

---------

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
Vinícius Andradeandmorluto authored and GitHub committed 2026-10-13 22:34:54 +08:00
1 parent 6e25cc3c76
commit 1e38a038c6
5 files changed
+217 -2

No files matched your search

@@ -83,6 +83,7 @@ export class JavaScriptAnalysisWorker {
readonly #resultBudgetBytes: number;
/** Null when the runtime enforces the V8 heap flags instead. */
readonly #processMemoryLimitBytes: number | null;
readonly #onStdinError = (): void => {};
readonly #onStdout = (chunk: Buffer | string): void => {
try {
this.#pending +=
@@ -784,20 +785,40 @@ export class JavaScriptAnalysisWorker {
if (this.#supervisor !== undefined) {
const supervisor = this.#supervisor;
const stopped = await supervisor.stop();
supervisor.launch.process.stdout?.off("data", this.#onStdout);
if (stopped.status === "incomplete") {
try {
const stdin = supervisor.launch.process.stdin;
if (
stdin !== undefined &&
stdin !== null &&
!stdin.destroyed &&
!stdin.writableEnded
) {
stdin.off("error", this.#onStdinError);
stdin.once("error", this.#onStdinError);
stdin.end();
}
} catch {
// Cooperative protocol stdin may already be closed or broken.
}
this.#resetState();
pendingCleanup.add(this);
return this.#cleanupError(stopped.reason, original);
}
supervisor.launch.process.stdout?.off("data", this.#onStdout);
supervisor.dispose();
this.#supervisor = undefined;
}
this.#resetState();
return undefined;
}
#resetState(): void {
this.#ready = false;
this.#frames = [];
this.#pending = "";
this.#decoder = new StringDecoder("utf8");
this.#protocolFailure = undefined;
return undefined;
}
}