



























@@ -483,6 +483,7 @@ export function runMeasuredCommandLive(params) {
483483let timedOut = false;
484484let settled = false;
485485let forceKillTimeout = null;
486+let forceKillAt = 0;
486487const maxBufferBytes = params.maxBufferBytes ?? COMMAND_OUTPUT_MAX_BUFFER_BYTES;
487488const maxRelayBytes = params.consoleOutputMaxBytes ?? maxBufferBytes;
488489const timeoutKillGraceMs = params.timeoutKillGraceMs ?? 5_000;
@@ -506,6 +507,29 @@ export function runMeasuredCommandLive(params) {
506507}
507508child.kill(signal);
508509};
510+const processGroupAlive = () => {
511+if (!useProcessGroup || !child.pid) {
512+return false;
513+}
514+try {
515+process.kill(-child.pid, 0);
516+return true;
517+} catch (error) {
518+return Boolean(error && error.code === "EPERM");
519+}
520+};
521+const waitForProcessGroupExit = async (timeoutMs) => {
522+const deadlineAt = Date.now() + timeoutMs;
523+while (Date.now() < deadlineAt) {
524+if (!processGroupAlive()) {
525+return true;
526+}
527+await new Promise((resolvePoll) => {
528+setTimeout(resolvePoll, 25);
529+});
530+}
531+return !processGroupAlive();
532+};
509533const parentSignalHandlers = new Map();
510534const removeParentSignalHandlers = () => {
511535for (const [signal, handler] of parentSignalHandlers) {
@@ -613,6 +637,7 @@ export function runMeasuredCommandLive(params) {
613637message: `Command timed out after ${params.timeoutMs}ms`,
614638};
615639killMeasuredProcess();
640+forceKillAt = Date.now() + timeoutKillGraceMs;
616641forceKillTimeout = setTimeout(() => {
617642killMeasuredProcess("SIGKILL");
618643}, timeoutKillGraceMs);
@@ -628,9 +653,6 @@ export function runMeasuredCommandLive(params) {
628653if (timeout) {
629654clearTimeout(timeout);
630655}
631-if (timedOut) {
632-killMeasuredProcess("SIGKILL");
633-}
634656if (forceKillTimeout) {
635657clearTimeout(forceKillTimeout);
636658}
@@ -673,14 +695,31 @@ export function runMeasuredCommandLive(params) {
673695 ...parseTimedMetrics(finalStderr, wallMs, mode),
674696});
675697};
698+const finishAfterTimeoutTeardown = async (status, signal) => {
699+const remainingGraceMs = Math.max(0, forceKillAt - Date.now());
700+if (remainingGraceMs > 0) {
701+await waitForProcessGroupExit(remainingGraceMs);
702+}
703+if (processGroupAlive()) {
704+killMeasuredProcess("SIGKILL");
705+await waitForProcessGroupExit(100);
706+}
707+finish(status, signal);
708+};
676709child.on("error", (error) => {
677710spawnError = {
678711code: typeof error.code === "string" ? error.code : null,
679712message: error.message,
680713};
681714finish(null, null);
682715});
683-child.on("close", (status, signal) => finish(status, signal));
716+child.on("close", (status, signal) => {
717+if (timedOut) {
718+void finishAfterTimeoutTeardown(status, signal);
719+return;
720+}
721+finish(status, signal);
722+});
684723});
685724}
686725此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。