mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
fix(plugins): abort sibling boundary prep steps
This commit is contained in:
@@ -33,11 +33,19 @@ export function createPrefixedOutputWriter(label, target) {
|
||||
};
|
||||
}
|
||||
|
||||
function runNodeStep(label, args, timeoutMs) {
|
||||
function abortSiblingSteps(abortController) {
|
||||
if (abortController && !abortController.signal.aborted) {
|
||||
abortController.abort();
|
||||
}
|
||||
}
|
||||
|
||||
export function runNodeStep(label, args, timeoutMs, params = {}) {
|
||||
const abortController = params.abortController;
|
||||
return new Promise((resolvePromise, rejectPromise) => {
|
||||
const child = spawn(process.execPath, args, {
|
||||
cwd: repoRoot,
|
||||
env: process.env,
|
||||
signal: abortController?.signal,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
@@ -52,6 +60,7 @@ function runNodeStep(label, args, timeoutMs) {
|
||||
settled = true;
|
||||
stdoutWriter.flush();
|
||||
stderrWriter.flush();
|
||||
abortSiblingSteps(abortController);
|
||||
rejectPromise(new Error(`${label} timed out after ${timeoutMs}ms`));
|
||||
}, timeoutMs);
|
||||
|
||||
@@ -71,6 +80,11 @@ function runNodeStep(label, args, timeoutMs) {
|
||||
settled = true;
|
||||
stdoutWriter.flush();
|
||||
stderrWriter.flush();
|
||||
if (error.name === "AbortError" && abortController?.signal.aborted) {
|
||||
rejectPromise(new Error(`${label} canceled after sibling failure`));
|
||||
return;
|
||||
}
|
||||
abortSiblingSteps(abortController);
|
||||
rejectPromise(new Error(`${label} failed to start: ${error.message}`));
|
||||
});
|
||||
child.on("close", (code) => {
|
||||
@@ -85,24 +99,36 @@ function runNodeStep(label, args, timeoutMs) {
|
||||
resolvePromise();
|
||||
return;
|
||||
}
|
||||
abortSiblingSteps(abortController);
|
||||
rejectPromise(new Error(`${label} failed with exit code ${code ?? 1}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function runNodeStepsInParallel(steps) {
|
||||
const abortController = new AbortController();
|
||||
const results = await Promise.allSettled(
|
||||
steps.map((step) => runNodeStep(step.label, step.args, step.timeoutMs, { abortController })),
|
||||
);
|
||||
const firstFailure = results.find((result) => result.status === "rejected");
|
||||
if (firstFailure) {
|
||||
throw firstFailure.reason;
|
||||
}
|
||||
}
|
||||
|
||||
export async function main() {
|
||||
try {
|
||||
await Promise.all([
|
||||
runNodeStep(
|
||||
"plugin-sdk boundary dts",
|
||||
[tscBin, "-p", "tsconfig.plugin-sdk.dts.json"],
|
||||
300_000,
|
||||
),
|
||||
runNodeStep(
|
||||
"plugin-sdk package boundary dts",
|
||||
[tscBin, "-p", "packages/plugin-sdk/tsconfig.json"],
|
||||
300_000,
|
||||
),
|
||||
await runNodeStepsInParallel([
|
||||
{
|
||||
label: "plugin-sdk boundary dts",
|
||||
args: [tscBin, "-p", "tsconfig.plugin-sdk.dts.json"],
|
||||
timeoutMs: 300_000,
|
||||
},
|
||||
{
|
||||
label: "plugin-sdk package boundary dts",
|
||||
args: [tscBin, "-p", "packages/plugin-sdk/tsconfig.json"],
|
||||
timeoutMs: 300_000,
|
||||
},
|
||||
]);
|
||||
await runNodeStep(
|
||||
"plugin-sdk boundary root shims",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createPrefixedOutputWriter } from "../../scripts/prepare-extension-package-boundary-artifacts.mjs";
|
||||
import {
|
||||
createPrefixedOutputWriter,
|
||||
runNodeStepsInParallel,
|
||||
} from "../../scripts/prepare-extension-package-boundary-artifacts.mjs";
|
||||
|
||||
describe("prepare-extension-package-boundary-artifacts", () => {
|
||||
it("prefixes each completed line and flushes the trailing partial line", () => {
|
||||
@@ -16,4 +19,25 @@ describe("prepare-extension-package-boundary-artifacts", () => {
|
||||
|
||||
expect(output).toBe("[boundary] first line\n[boundary] second line\n[boundary] third");
|
||||
});
|
||||
|
||||
it("aborts sibling steps after the first failure", async () => {
|
||||
const startedAt = Date.now();
|
||||
|
||||
await expect(
|
||||
runNodeStepsInParallel([
|
||||
{
|
||||
label: "fail-fast",
|
||||
args: ["--eval", "setTimeout(() => process.exit(2), 10)"],
|
||||
timeoutMs: 5_000,
|
||||
},
|
||||
{
|
||||
label: "slow-step",
|
||||
args: ["--eval", "setTimeout(() => {}, 10_000)"],
|
||||
timeoutMs: 5_000,
|
||||
},
|
||||
]),
|
||||
).rejects.toThrow("fail-fast failed with exit code 2");
|
||||
|
||||
expect(Date.now() - startedAt).toBeLessThan(2_000);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user