mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-14 16:07:52 +00:00
fix(boot): count the startup timeout only while the window shows
A window behind others or on another Space gets no animation frames, and the splash waits for two of them before startup finishes. The 30-second timeout kept running meanwhile and reported a healthy but slow start, such as a cold dev build, as "OpenIDEA could not start". It now pauses while the document is hidden and resumes with the time left.
This commit is contained in:
+23
-4
@@ -142,11 +142,30 @@
|
||||
window.removeEventListener("unhandledrejection", onRejection);
|
||||
window.removeEventListener("openidea:boot-error", onBootError);
|
||||
window.removeEventListener("openidea:boot-ready", onReady);
|
||||
document.removeEventListener("visibilitychange", onVisibility);
|
||||
};
|
||||
const timer = window.setTimeout(
|
||||
() => show(rejection === undefined ? text.timeout : `${text.timeout}\n\nUnhandled rejection: ${rejection}`),
|
||||
30_000,
|
||||
);
|
||||
// The timeout counts only while the window shows: a hidden or covered window gets no
|
||||
// animation frames, and the splash waits for those to finish startup.
|
||||
let remaining = 30_000;
|
||||
let armedAt = 0;
|
||||
let timer;
|
||||
const arm = () => {
|
||||
if (failed || ready || timer !== undefined || document.hidden) return;
|
||||
armedAt = Date.now();
|
||||
timer = window.setTimeout(
|
||||
() => show(rejection === undefined ? text.timeout : `${text.timeout}\n\nUnhandled rejection: ${rejection}`),
|
||||
remaining,
|
||||
);
|
||||
};
|
||||
const onVisibility = () => {
|
||||
if (!document.hidden) return arm();
|
||||
if (timer === undefined) return;
|
||||
window.clearTimeout(timer);
|
||||
timer = undefined;
|
||||
remaining -= Date.now() - armedAt;
|
||||
};
|
||||
arm();
|
||||
document.addEventListener("visibilitychange", onVisibility);
|
||||
window.addEventListener("error", onError, true);
|
||||
window.addEventListener("unhandledrejection", onRejection);
|
||||
window.addEventListener("openidea:boot-error", onBootError);
|
||||
|
||||
@@ -95,6 +95,27 @@ it("reports the first rejection when startup then times out", () => {
|
||||
expect(details).not.toContain("later rejection");
|
||||
});
|
||||
|
||||
it("counts the startup timeout only while the window shows", () => {
|
||||
const hidden = (value: boolean) => {
|
||||
Object.defineProperty(document, "hidden", { configurable: true, value });
|
||||
document.dispatchEvent(new Event("visibilitychange"));
|
||||
};
|
||||
try {
|
||||
vi.advanceTimersByTime(20_000);
|
||||
// Behind another window: no frames, so the splash can't finish; that isn't a failure.
|
||||
hidden(true);
|
||||
vi.advanceTimersByTime(60_000);
|
||||
expect(document.getElementById("boot-error")).toBeNull();
|
||||
hidden(false);
|
||||
vi.advanceTimersByTime(9_000);
|
||||
expect(document.getElementById("boot-error")).toBeNull();
|
||||
vi.advanceTimersByTime(1_000);
|
||||
expect(document.querySelector("textarea")?.value).toContain("Startup did not finish within 30 seconds.");
|
||||
} finally {
|
||||
Object.defineProperty(document, "hidden", { configurable: true, value: false });
|
||||
}
|
||||
});
|
||||
|
||||
it("preserves the first failure", () => {
|
||||
window.dispatchEvent(new ErrorEvent("error", { error: new Error("startup failed") }));
|
||||
window.dispatchEvent(new ErrorEvent("error", { message: "later failure" }));
|
||||
|
||||
Reference in New Issue
Block a user