























@@ -700,4 +700,71 @@ describe("runTsdownBuildInvocation", () => {
700700}
701701},
702702);
703+704+it.skipIf(process.platform === "win32")(
705+"preserves timeout grace when descendant processes exit cleanly",
706+async () => {
707+const rootDir = createTempDir("openclaw-tsdown-timeout-clean-");
708+const readyPath = path.join(rootDir, "child.ready");
709+const cleanupPath = path.join(rootDir, "child.cleanup");
710+const childPidPath = path.join(rootDir, "child.pid");
711+const childScript = [
712+"const fs = require('node:fs');",
713+`fs.writeFileSync(${JSON.stringify(childPidPath)}, String(process.pid));`,
714+"process.on('SIGTERM', () => {",
715+" setTimeout(() => {",
716+` fs.writeFileSync(${JSON.stringify(cleanupPath)}, 'clean');`,
717+" process.exit(0);",
718+" }, 75);",
719+"});",
720+`fs.writeFileSync(${JSON.stringify(readyPath)}, 'ready');`,
721+"setInterval(() => {}, 1000);",
722+].join("");
723+const parentScript = [
724+"const { spawn } = require('node:child_process');",
725+`spawn(process.execPath, ['-e', ${JSON.stringify(childScript)}], { stdio: 'ignore' });`,
726+"process.on('SIGTERM', () => process.exit(0));",
727+"setInterval(() => {}, 1000);",
728+].join("");
729+let childPid = 0;
730+731+try {
732+const output = createWriteSink();
733+const startedAt = Date.now();
734+const runPromise = runTsdownBuildInvocation(
735+{
736+command: process.execPath,
737+args: ["-e", parentScript],
738+options: {
739+stdio: ["ignore", "pipe", "pipe"],
740+shell: false,
741+env: process.env,
742+},
743+},
744+{
745+stdout: output.sink,
746+stderr: output.sink,
747+env: {
748+ ...process.env,
749+OPENCLAW_TSDOWN_HEARTBEAT_MS: "0",
750+OPENCLAW_TSDOWN_TIMEOUT_MS: "1000",
751+},
752+},
753+);
754+755+await waitForFile(readyPath, 2_000);
756+childPid = Number.parseInt(fs.readFileSync(childPidPath, "utf8"), 10);
757+const result = await runPromise;
758+759+expect(result.timedOut).toBe(true);
760+expect(fs.readFileSync(cleanupPath, "utf8")).toBe("clean");
761+expect(Date.now() - startedAt).toBeLessThan(1_700);
762+await waitForDead(childPid, 2_000);
763+} finally {
764+if (childPid && isProcessAlive(childPid)) {
765+process.kill(childPid, "SIGKILL");
766+}
767+}
768+},
769+);
703770});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。