mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 15:59:30 +00:00
fix(scripts): report startup help stream errors when pipes fail (#102436)
* fix(scripts): fail startup help rendering on stream errors * fix(scripts): preserve startup render failure provenance --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
parent
ecc2cffad8
commit
a5f5282816
2 changed files with 86 additions and 1 deletions
|
|
@ -382,14 +382,16 @@ async function spawnText(
|
|||
failureMessage: string;
|
||||
killGraceMs?: number;
|
||||
maxOutputBytes?: number;
|
||||
spawnProcess?: typeof spawn;
|
||||
timeoutMs: number;
|
||||
},
|
||||
): Promise<string> {
|
||||
const maxOutputBytes = options.maxOutputBytes ?? COMMAND_HELP_RENDER_MAX_OUTPUT_BYTES;
|
||||
const killGraceMs = options.killGraceMs ?? COMMAND_HELP_RENDER_KILL_GRACE_MS;
|
||||
const spawnProcess = options.spawnProcess ?? spawn;
|
||||
const useProcessGroup = process.platform !== "win32";
|
||||
return await new Promise((resolve, reject) => {
|
||||
const child = spawn(process.execPath, args, {
|
||||
const child = spawnProcess(process.execPath, args, {
|
||||
cwd: options.cwd,
|
||||
detached: useProcessGroup,
|
||||
env: options.env,
|
||||
|
|
@ -399,6 +401,7 @@ async function spawnText(
|
|||
let stderr = "";
|
||||
let outputBytes = 0;
|
||||
let outputExceeded = false;
|
||||
let outputStreamError: { streamName: "stdout" | "stderr"; error: Error } | undefined;
|
||||
let settled = false;
|
||||
let timedOut = false;
|
||||
let waitingForKillGrace = false;
|
||||
|
|
@ -483,6 +486,15 @@ async function spawnText(
|
|||
};
|
||||
const finishClose = (result: { code: number | null; signal: NodeJS.Signals | null }) => {
|
||||
settle(() => {
|
||||
if (outputStreamError) {
|
||||
reject(
|
||||
new Error(
|
||||
`${options.failureMessage}: ${outputStreamError.streamName} read error: ${outputStreamError.error.message}`,
|
||||
{ cause: outputStreamError.error },
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (result.code === 0 && !timedOut && !outputExceeded) {
|
||||
resolve(stdout);
|
||||
return;
|
||||
|
|
@ -522,6 +534,15 @@ async function spawnText(
|
|||
signalChild("SIGTERM");
|
||||
scheduleKill();
|
||||
};
|
||||
const failOutputStream = (streamName: "stdout" | "stderr", error: Error) => {
|
||||
// Keep the first stop cause: killing for a timeout or output cap can make
|
||||
// the stdio pipes fail secondarily while the child is shutting down.
|
||||
if (outputStreamError || timedOut || outputExceeded) {
|
||||
return;
|
||||
}
|
||||
outputStreamError = { streamName, error };
|
||||
requestStop();
|
||||
};
|
||||
const timeout = setTimeout(() => {
|
||||
timedOut = true;
|
||||
requestStop();
|
||||
|
|
@ -553,6 +574,12 @@ async function spawnText(
|
|||
}
|
||||
stderr += chunk;
|
||||
});
|
||||
child.stdout.once("error", (error: Error) => {
|
||||
failOutputStream("stdout", error);
|
||||
});
|
||||
child.stderr.once("error", (error: Error) => {
|
||||
failOutputStream("stderr", error);
|
||||
});
|
||||
child.once("error", (error) => {
|
||||
settle(() => {
|
||||
reject(error);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue