mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(e2e): forward sighup in node watchdogs
This commit is contained in:
@@ -99,6 +99,7 @@ const forwardSignal = (signal) => {
|
||||
};
|
||||
process.once("SIGINT", forwardSignal);
|
||||
process.once("SIGTERM", forwardSignal);
|
||||
process.once("SIGHUP", forwardSignal);
|
||||
child.on("exit", (code, signal) => {
|
||||
clearTimeout(timer);
|
||||
if (parentSignalTimer) {
|
||||
|
||||
@@ -137,6 +137,7 @@ const forwardSignal = (signal) => {
|
||||
};
|
||||
process.once("SIGINT", forwardSignal);
|
||||
process.once("SIGTERM", forwardSignal);
|
||||
process.once("SIGHUP", forwardSignal);
|
||||
child.on("close", (code, signal) => {
|
||||
clearTimeout(timer);
|
||||
if (parentSignalTimer) {
|
||||
|
||||
@@ -517,29 +517,33 @@ stderr="$(<"$TMPDIR/stderr")"
|
||||
}
|
||||
});
|
||||
|
||||
it("escalates Docker watchdog children that ignore parent termination", () => {
|
||||
const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-node-signal-"));
|
||||
for (const [shellSignal, expectedStatus] of [
|
||||
["TERM", "143"],
|
||||
["HUP", "129"],
|
||||
] as const) {
|
||||
it(`escalates Docker watchdog children that ignore parent SIG${shellSignal}`, () => {
|
||||
const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-node-signal-"));
|
||||
|
||||
try {
|
||||
const binDir = join(workDir, "bin");
|
||||
mkdirSync(binDir);
|
||||
writeFileSync(
|
||||
join(binDir, "node"),
|
||||
`#!/bin/bash\nexec ${shellQuote(process.execPath)} "$@"\n`,
|
||||
);
|
||||
writeFileSync(
|
||||
join(binDir, "docker"),
|
||||
`#!/bin/bash
|
||||
try {
|
||||
const binDir = join(workDir, "bin");
|
||||
mkdirSync(binDir);
|
||||
writeFileSync(
|
||||
join(binDir, "node"),
|
||||
`#!/bin/bash\nexec ${shellQuote(process.execPath)} "$@"\n`,
|
||||
);
|
||||
writeFileSync(
|
||||
join(binDir, "docker"),
|
||||
`#!/bin/bash
|
||||
printf "%s\\n" "$$" >"$TMPDIR/docker-pid"
|
||||
printf "%s\\n" "$PPID" >"$TMPDIR/watchdog-pid"
|
||||
trap "" TERM
|
||||
trap "" TERM HUP
|
||||
while true; do /bin/sleep 1; done
|
||||
`,
|
||||
);
|
||||
chmodSync(join(binDir, "node"), 0o755);
|
||||
chmodSync(join(binDir, "docker"), 0o755);
|
||||
const rootDir = process.cwd();
|
||||
const script = `
|
||||
);
|
||||
chmodSync(join(binDir, "node"), 0o755);
|
||||
chmodSync(join(binDir, "docker"), 0o755);
|
||||
const rootDir = process.cwd();
|
||||
const script = `
|
||||
set -euo pipefail
|
||||
ROOT_DIR=${shellQuote(rootDir)}
|
||||
TMPDIR=${shellQuote(workDir)}
|
||||
@@ -558,12 +562,12 @@ for ((i = 0; i < 100; i += 1)); do
|
||||
done
|
||||
[ -s "$TMPDIR/docker-pid" ]
|
||||
[ -s "$TMPDIR/watchdog-pid" ]
|
||||
kill -TERM "$(/bin/cat "$TMPDIR/watchdog-pid")"
|
||||
kill -${shellSignal} "$(/bin/cat "$TMPDIR/watchdog-pid")"
|
||||
set +e
|
||||
wait "$watchdog_pid"
|
||||
status="$?"
|
||||
set -e
|
||||
[ "$status" = "143" ]
|
||||
[ "$status" = "${expectedStatus}" ]
|
||||
docker_pid="$(/bin/cat "$TMPDIR/docker-pid")"
|
||||
for ((i = 0; i < 100; i += 1)); do
|
||||
kill -0 "$docker_pid" 2>/dev/null || exit 0
|
||||
@@ -573,11 +577,12 @@ echo "docker child still alive after watchdog termination" >&2
|
||||
exit 1
|
||||
`;
|
||||
|
||||
execFileSync("bash", ["-lc", script], { encoding: "utf8" });
|
||||
} finally {
|
||||
rmSync(workDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
execFileSync("bash", ["-lc", script], { encoding: "utf8" });
|
||||
} finally {
|
||||
rmSync(workDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
it("uses plain timeout when kill-after is unsupported", () => {
|
||||
const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-plain-timeout-"));
|
||||
|
||||
@@ -374,28 +374,33 @@ describe("scripts/lib/openclaw-e2e-instance.sh", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("escalates Node watchdog children that ignore parent termination", () => {
|
||||
const tempDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), "openclaw-e2e-instance-node-watchdog-signal-"),
|
||||
);
|
||||
try {
|
||||
writeNodeShim(tempDir);
|
||||
const childPath = path.join(tempDir, "ignore-term.cjs");
|
||||
const pidPath = path.join(tempDir, "child.pid");
|
||||
const watchdogPidPath = path.join(tempDir, "watchdog.pid");
|
||||
fs.writeFileSync(
|
||||
childPath,
|
||||
[
|
||||
"const fs = require('node:fs');",
|
||||
"fs.writeFileSync(process.argv[2], String(process.pid));",
|
||||
"fs.writeFileSync(process.argv[3], String(process.ppid));",
|
||||
"process.on('SIGTERM', () => {});",
|
||||
"setInterval(() => {}, 1000);",
|
||||
"",
|
||||
].join("\n"),
|
||||
for (const [shellSignal, expectedStatus] of [
|
||||
["TERM", "143"],
|
||||
["HUP", "129"],
|
||||
] as const) {
|
||||
it(`escalates Node watchdog children that ignore parent SIG${shellSignal}`, () => {
|
||||
const tempDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), "openclaw-e2e-instance-node-watchdog-signal-"),
|
||||
);
|
||||
try {
|
||||
writeNodeShim(tempDir);
|
||||
const childPath = path.join(tempDir, "ignore-term.cjs");
|
||||
const pidPath = path.join(tempDir, "child.pid");
|
||||
const watchdogPidPath = path.join(tempDir, "watchdog.pid");
|
||||
fs.writeFileSync(
|
||||
childPath,
|
||||
[
|
||||
"const fs = require('node:fs');",
|
||||
"fs.writeFileSync(process.argv[2], String(process.pid));",
|
||||
"fs.writeFileSync(process.argv[3], String(process.ppid));",
|
||||
"process.on('SIGTERM', () => {});",
|
||||
"process.on('SIGHUP', () => {});",
|
||||
"setInterval(() => {}, 1000);",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const script = `
|
||||
const script = `
|
||||
set -euo pipefail
|
||||
source ${shellQuote(helperPath)}
|
||||
export OPENCLAW_E2E_TIMEOUT_KILL_GRACE_MS=100
|
||||
@@ -407,12 +412,12 @@ for ((i = 0; i < 100; i += 1)); do
|
||||
done
|
||||
[ -s ${shellQuote(pidPath)} ]
|
||||
[ -s ${shellQuote(watchdogPidPath)} ]
|
||||
kill -TERM "$(/bin/cat ${shellQuote(watchdogPidPath)})"
|
||||
kill -${shellSignal} "$(/bin/cat ${shellQuote(watchdogPidPath)})"
|
||||
set +e
|
||||
wait "$wrapper_pid"
|
||||
status="$?"
|
||||
set -e
|
||||
[ "$status" = "143" ]
|
||||
[ "$status" = "${expectedStatus}" ]
|
||||
child_pid="$(/bin/cat ${shellQuote(pidPath)})"
|
||||
for ((i = 0; i < 100; i += 1)); do
|
||||
kill -0 "$child_pid" 2>/dev/null || exit 0
|
||||
@@ -422,19 +427,20 @@ echo "child still alive after watchdog termination" >&2
|
||||
exit 1
|
||||
`;
|
||||
|
||||
const result = spawnSync("/bin/bash", ["-c", script], {
|
||||
encoding: "utf8",
|
||||
env: shellTestEnv({
|
||||
PATH: tempDir,
|
||||
}),
|
||||
timeout: 5_000,
|
||||
});
|
||||
const result = spawnSync("/bin/bash", ["-c", script], {
|
||||
encoding: "utf8",
|
||||
env: shellTestEnv({
|
||||
PATH: tempDir,
|
||||
}),
|
||||
timeout: 5_000,
|
||||
});
|
||||
|
||||
expectShellSuccess(result);
|
||||
} finally {
|
||||
fs.rmSync(tempDir, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
expectShellSuccess(result);
|
||||
} finally {
|
||||
fs.rmSync(tempDir, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
it("terminates only the tracked gateway process", () => {
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-e2e-gateway-terminate-"));
|
||||
|
||||
Reference in New Issue
Block a user