mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-30 00:28:42 +00:00
fix: retry config snapshot after rejection (#83944)
Summary: - This PR clears the cached CLI config snapshot promise when a read rejects, adds a reject-retry-cache regression test, and adds an Unreleased changelog entry. - Reproducibility: yes. Current main clearly caches the first snapshot-read promise, and the source PR supplied a focused reject, recover, cached-success probe; I did not rerun it in this read-only review. Automerge notes: - PR branch already contained follow-up commit before automerge: fix: retry config snapshot after rejection Validation: - ClawSweeper review passed for heada46b5ec5c7. - Required merge gates passed before the squash merge. Prepared head SHA:a46b5ec5c7Review: https://github.com/openclaw/openclaw/pull/83944#issuecomment-4484051060 Co-authored-by: honor2030 <19909783+honor2030@users.noreply.github.com> Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -130,6 +130,31 @@ describe("ensureConfigReady", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("retries the cached config snapshot after a read rejection", async () => {
|
||||
const originalVitest = process.env.VITEST;
|
||||
process.env.VITEST = "false";
|
||||
const transientError = new Error("temporary config read failure");
|
||||
const recoveredSnapshot = makeSnapshot();
|
||||
readConfigFileSnapshotMock
|
||||
.mockRejectedValueOnce(transientError)
|
||||
.mockResolvedValueOnce(recoveredSnapshot);
|
||||
|
||||
try {
|
||||
await expect(runEnsureConfigReady(["status"])).rejects.toThrow(transientError);
|
||||
await expect(runEnsureConfigReady(["status"])).resolves.toBeDefined();
|
||||
await expect(runEnsureConfigReady(["status"])).resolves.toBeDefined();
|
||||
} finally {
|
||||
if (originalVitest === undefined) {
|
||||
delete process.env.VITEST;
|
||||
} else {
|
||||
process.env.VITEST = originalVitest;
|
||||
}
|
||||
}
|
||||
|
||||
expect(readConfigFileSnapshotMock).toHaveBeenCalledTimes(2);
|
||||
expect(setRuntimeConfigSnapshotMock).toHaveBeenCalledWith(undefined, undefined);
|
||||
});
|
||||
|
||||
it("exits for invalid config on non-allowlisted commands", async () => {
|
||||
setInvalidSnapshot();
|
||||
const runtime = await runEnsureConfigReady(["message"]);
|
||||
|
||||
@@ -30,7 +30,15 @@ async function getConfigSnapshot() {
|
||||
if (process.env.VITEST === "true") {
|
||||
return readConfigFileSnapshot();
|
||||
}
|
||||
configSnapshotPromise ??= readConfigFileSnapshot();
|
||||
if (!configSnapshotPromise) {
|
||||
const pendingSnapshot = readConfigFileSnapshot();
|
||||
configSnapshotPromise = pendingSnapshot;
|
||||
pendingSnapshot.catch(() => {
|
||||
if (configSnapshotPromise === pendingSnapshot) {
|
||||
configSnapshotPromise = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return configSnapshotPromise;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user