mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-07 10:34:44 +00:00
fix(scripts): kill managed child trees on windows
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Runs child commands with process-group signal forwarding and Windows shell normalization.
|
||||
import { spawn } from "node:child_process";
|
||||
import { spawn, spawnSync } from "node:child_process";
|
||||
import { constants as osConstants } from "node:os";
|
||||
import { buildCmdExeCommandLine } from "../windows-cmd-helpers.mjs";
|
||||
|
||||
@@ -22,14 +22,19 @@ export function signalExitCode(signal) {
|
||||
/**
|
||||
* @param {import("node:child_process").ChildProcess} child
|
||||
* @param {NodeJS.Signals} [signal]
|
||||
* @param {{ platform?: NodeJS.Platform; runTaskkill?: typeof spawnSync }} [options]
|
||||
*/
|
||||
function terminateManagedChild(child, signal = "SIGTERM") {
|
||||
export function terminateManagedChild(
|
||||
child,
|
||||
signal = "SIGTERM",
|
||||
{ platform = process.platform, runTaskkill = spawnSync } = {},
|
||||
) {
|
||||
if (!child.pid) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (process.platform !== "win32") {
|
||||
if (platform !== "win32") {
|
||||
process.kill(-child.pid, signal);
|
||||
return;
|
||||
}
|
||||
@@ -44,6 +49,17 @@ function terminateManagedChild(child, signal = "SIGTERM") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (platform === "win32") {
|
||||
const args = ["/PID", String(child.pid), "/T"];
|
||||
if (signal === "SIGKILL") {
|
||||
args.push("/F");
|
||||
}
|
||||
const result = runTaskkill("taskkill", args, { stdio: "ignore" });
|
||||
if (!result?.error && result?.status === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
child.kill(signal);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { setTimeout as delay } from "node:timers/promises";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
createManagedCommandSpawnSpec,
|
||||
runManagedCommand,
|
||||
signalExitCode,
|
||||
terminateManagedChild,
|
||||
} from "../../scripts/lib/managed-child-process.mjs";
|
||||
import { createScriptTestHarness } from "./test-helpers.js";
|
||||
|
||||
@@ -110,6 +111,31 @@ describe("managed-child-process", () => {
|
||||
).toThrow("unsafe Windows cmd.exe argument detected");
|
||||
});
|
||||
|
||||
it("signals Windows managed process trees with taskkill", () => {
|
||||
const child = {
|
||||
kill: vi.fn(),
|
||||
pid: 12345,
|
||||
};
|
||||
const runTaskkill = vi.fn(() => ({ error: undefined, status: 0 }));
|
||||
|
||||
terminateManagedChild(child, "SIGTERM", {
|
||||
platform: "win32",
|
||||
runTaskkill,
|
||||
});
|
||||
expect(runTaskkill).toHaveBeenNthCalledWith(1, "taskkill", ["/PID", "12345", "/T"], {
|
||||
stdio: "ignore",
|
||||
});
|
||||
|
||||
terminateManagedChild(child, "SIGKILL", {
|
||||
platform: "win32",
|
||||
runTaskkill,
|
||||
});
|
||||
expect(runTaskkill).toHaveBeenNthCalledWith(2, "taskkill", ["/PID", "12345", "/T", "/F"], {
|
||||
stdio: "ignore",
|
||||
});
|
||||
expect(child.kill).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shares process signal listeners across parallel managed commands", async () => {
|
||||
const signals = ["SIGHUP", "SIGINT", "SIGTERM"] as const;
|
||||
const baseline = new Map(signals.map((signal) => [signal, process.listenerCount(signal)]));
|
||||
|
||||
Reference in New Issue
Block a user