fix: retry bundled runtime dependency staging

This commit is contained in:
Shakker 2026-03-30 23:18:32 +01:00 committed by Shakker
parent cefa191417
commit d46f64199a
2 changed files with 86 additions and 5 deletions

View File

@ -266,10 +266,28 @@ function installPluginRuntimeDeps(params) {
}
}
function installPluginRuntimeDepsWithRetries(params) {
const { attempts = 3 } = params;
let lastError;
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
params.install({ ...params.installParams, attempt });
return;
} catch (error) {
lastError = error;
if (attempt === attempts) {
break;
}
}
}
throw lastError;
}
export function stageBundledPluginRuntimeDeps(params = {}) {
const repoRoot = params.cwd ?? params.repoRoot ?? process.cwd();
const installPluginRuntimeDepsImpl =
params.installPluginRuntimeDepsImpl ?? installPluginRuntimeDeps;
const installAttempts = params.installAttempts ?? 3;
for (const pluginDir of listBundledPluginRuntimeDirs(repoRoot)) {
const pluginId = path.basename(pluginDir);
const packageJson = sanitizeBundledManifestForRuntimeInstall(pluginDir);
@ -285,11 +303,15 @@ export function stageBundledPluginRuntimeDeps(params = {}) {
if (fs.existsSync(nodeModulesDir) && stamp?.fingerprint === fingerprint) {
continue;
}
installPluginRuntimeDepsImpl({
fingerprint,
packageJson,
pluginDir,
pluginId,
installPluginRuntimeDepsWithRetries({
attempts: installAttempts,
install: installPluginRuntimeDepsImpl,
installParams: {
fingerprint,
packageJson,
pluginDir,
pluginId,
},
});
}
}

View File

@ -228,4 +228,63 @@ describe("stageBundledPluginRuntimeDeps", () => {
expect(installCount).toBe(2);
expect(fs.readFileSync(path.join(pluginDir, "node_modules", "marker.txt"), "utf8")).toBe("2\n");
});
it("retries transient runtime dependency staging failures before surfacing an error", () => {
const { pluginDir, repoRoot } = createBundledPluginFixture({
packageJson: {
name: "@openclaw/fixture-plugin",
version: "1.0.0",
dependencies: { "left-pad": "1.3.0" },
openclaw: { bundle: { stageRuntimeDependencies: true } },
},
});
let installCount = 0;
stageBundledPluginRuntimeDeps({
cwd: repoRoot,
installPluginRuntimeDepsImpl: ({ fingerprint }: { fingerprint: string }) => {
installCount += 1;
if (installCount < 3) {
throw new Error(`attempt ${installCount} failed`);
}
const nodeModulesDir = path.join(pluginDir, "node_modules");
fs.mkdirSync(nodeModulesDir, { recursive: true });
fs.writeFileSync(path.join(nodeModulesDir, "marker.txt"), "ok\n", "utf8");
fs.writeFileSync(
path.join(pluginDir, ".openclaw-runtime-deps-stamp.json"),
`${JSON.stringify({ fingerprint }, null, 2)}\n`,
"utf8",
);
},
});
expect(installCount).toBe(3);
expect(fs.readFileSync(path.join(pluginDir, "node_modules", "marker.txt"), "utf8")).toBe(
"ok\n",
);
});
it("surfaces the last staging error after exhausting retries", () => {
const { repoRoot } = createBundledPluginFixture({
packageJson: {
name: "@openclaw/fixture-plugin",
version: "1.0.0",
dependencies: { "left-pad": "1.3.0" },
openclaw: { bundle: { stageRuntimeDependencies: true } },
},
});
let installCount = 0;
expect(() =>
stageBundledPluginRuntimeDeps({
cwd: repoRoot,
installAttempts: 2,
installPluginRuntimeDepsImpl: () => {
installCount += 1;
throw new Error(`attempt ${installCount} failed`);
},
}),
).toThrow("attempt 2 failed");
expect(installCount).toBe(2);
});
});