fix(ui): bound mount recovery probes (#108163)

Co-authored-by: Peter Steinberger <peter@steipete.me>
This commit is contained in:
Alix-007
2026-07-16 09:51:42 +08:00
committed by GitHub
parent a14fad5ff8
commit 5c97107c7a
2 changed files with 44 additions and 4 deletions
+12 -1
View File
@@ -339,14 +339,25 @@
recoveryInFlight = true;
recoveryAttempt += 1;
documentUrl.searchParams.set("openclaw_mount_recovery", String(Date.now()));
var recoveryController = new AbortController();
var requestTimer = window.setTimeout(function () {
recoveryController.abort();
}, delay);
window
.fetch(documentUrl.href, { cache: "no-store", credentials: "same-origin" })
.fetch(documentUrl.href, {
cache: "no-store",
credentials: "same-origin",
signal: recoveryController.signal,
})
.then(function (response) {
if (!response.ok) throw new Error("gateway unavailable");
window.location.replace(documentUrl.href);
})
.catch(function () {
finishRecoveryAttempt();
})
.finally(function () {
window.clearTimeout(requestTimer);
});
}
+32 -3
View File
@@ -125,10 +125,39 @@ describe("Control UI mount fallback", () => {
await vi.waitFor(() => expect(fetch).toHaveBeenCalled());
expect(fetch).toHaveBeenNthCalledWith(1, expect.stringContaining("openclaw_mount_recovery="), {
cache: "no-store",
credentials: "same-origin",
expect(fetch).toHaveBeenNthCalledWith(
1,
expect.stringContaining("openclaw_mount_recovery="),
expect.objectContaining({
cache: "no-store",
credentials: "same-origin",
signal: expect.any(frameWindow.AbortSignal),
}),
);
});
it("times out stalled recovery probes so automatic retries can continue", async () => {
const frameWindow = createIsolatedWindow();
const signals: AbortSignal[] = [];
const fetch = vi.fn((_url: string, init?: RequestInit) => {
const signal = init?.signal;
if (!(signal instanceof frameWindow.AbortSignal)) {
throw new Error("Expected recovery probe to include an abort signal");
}
signals.push(signal);
return new Promise<Response>((_resolve, reject) => {
signal.addEventListener("abort", () => reject(new Error("request aborted")), {
once: true,
});
});
});
Object.defineProperty(frameWindow, "fetch", { configurable: true, value: fetch });
installFallbackShell(frameWindow, await readIndexHtmlWithDelay(1));
await vi.waitFor(() => expect(fetch).toHaveBeenCalledTimes(6));
expect(signals).toHaveLength(6);
await vi.waitFor(() => expect(signals.every((signal) => signal.aborted)).toBe(true));
});
it("bounds automatic recovery attempts while the gateway is unavailable", async () => {