Skip to content

Commit b14786c

Browse files
committed
fix(updater): align GitHub repo with CI releases; retry on 502/503
- Point build.publish and zip/latest URLs to HyperlinksSpaceProgram (same repo as Windows release workflow), not HyperlinksSpaceBot. - Retry checkForUpdates up to 4 times with backoff on transient GitHub gateway errors (502/503/504, Unicorn HTML) and suppress error UI while retries are in flight. Made-with: Cursor
1 parent cd40cd0 commit b14786c

2 files changed

Lines changed: 60 additions & 4 deletions

File tree

app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
"publish": {
9696
"provider": "github",
9797
"owner": "HyperlinksSpace",
98-
"repo": "HyperlinksSpaceBot"
98+
"repo": "HyperlinksSpaceProgram"
9999
}
100100
},
101101
"dependencies": {

app/windows/build.cjs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,32 @@ const { spawn } = require("child_process");
1616
const { pathToFileURL } = require("url");
1717

1818
const UPDATE_GITHUB_OWNER = "HyperlinksSpace";
19-
const UPDATE_GITHUB_REPO = "HyperlinksSpaceBot";
19+
/** Must match `build.publish.repo` and the repo where CI uploads releases. */
20+
const UPDATE_GITHUB_REPO = "HyperlinksSpaceProgram";
2021
const ZIP_LATEST_YML = "zip-latest.yml";
2122
/** Same pattern as package.json build.win.artifactName for the zip target. */
2223
const WIN_PORTABLE_ZIP_PREFIX = "HyperlinksSpaceApp_";
2324
const LATEST_YML = "latest.yml";
2425

26+
function sleep(ms) {
27+
return new Promise((resolve) => setTimeout(resolve, ms));
28+
}
29+
30+
/** GitHub sometimes returns 502 HTML (Unicorn) or other gateway errors; worth retrying. */
31+
function isTransientGithubUpdateError(err) {
32+
if (!err) return false;
33+
const code = err.statusCode ?? err.status;
34+
if (code === 502 || code === 503 || code === 504) return true;
35+
const msg = String(err.message || err);
36+
if (
37+
/\b502\b|\b503\b|\b504\b|Bad Gateway|Service Unavailable|Gateway Timeout|taking too long|ECONNRESET|ETIMEDOUT/i.test(
38+
msg,
39+
)
40+
)
41+
return true;
42+
return false;
43+
}
44+
2545
/**
2646
* Prefer zip-latest.yml (has sha512 for the zip). If missing (404), use latest.yml + inferred zip name.
2747
* @returns {{ version: string, fileName: string, sha512: string | null, source: string }}
@@ -308,6 +328,25 @@ function setupAutoUpdater() {
308328
const { autoUpdater } = require("electron-updater");
309329
let manualCheckInProgress = false;
310330
let manualDownloadInProgress = false;
331+
let updaterCheckRetrying = false;
332+
333+
const checkForUpdatesWithRetry = async (attempts = 4) => {
334+
let lastErr;
335+
for (let i = 0; i < attempts; i++) {
336+
try {
337+
return await autoUpdater.checkForUpdates();
338+
} catch (e) {
339+
lastErr = e;
340+
if (!isTransientGithubUpdateError(e) || i === attempts - 1) throw e;
341+
const delayMs = 1500 * 2 ** i;
342+
log(
343+
`[updater] transient GitHub/update error (${i + 1}/${attempts}), retry in ${delayMs}ms: ${e?.message || e}`,
344+
);
345+
await sleep(delayMs);
346+
}
347+
}
348+
throw lastErr;
349+
};
311350
const currentVersion = app.getVersion();
312351
const currentVersionHtml = String(currentVersion)
313352
.replace(/&/g, "&amp;")
@@ -887,6 +926,9 @@ function setupAutoUpdater() {
887926

888927
autoUpdater.on("error", (err) => {
889928
log(`[updater] error: ${err?.message || String(err)}`);
929+
if (updaterCheckRetrying && isTransientGithubUpdateError(err)) {
930+
return;
931+
}
890932
if (manualCheckInProgress || manualDownloadInProgress) {
891933
manualCheckInProgress = false;
892934
manualDownloadInProgress = false;
@@ -925,7 +967,12 @@ function setupAutoUpdater() {
925967
showActions: false,
926968
installEnabled: false,
927969
});
928-
await autoUpdater.checkForUpdates();
970+
updaterCheckRetrying = true;
971+
try {
972+
await checkForUpdatesWithRetry();
973+
} finally {
974+
updaterCheckRetrying = false;
975+
}
929976
} catch (e) {
930977
manualCheckInProgress = false;
931978
manualDownloadInProgress = false;
@@ -953,7 +1000,16 @@ function setupAutoUpdater() {
9531000
const markAndCheck = () => {
9541001
lastCheckAt = Date.now();
9551002
log("[updater] scheduled checkForUpdates()");
956-
void autoUpdater.checkForUpdates();
1003+
void (async () => {
1004+
updaterCheckRetrying = true;
1005+
try {
1006+
await checkForUpdatesWithRetry();
1007+
} catch (e) {
1008+
log(`[updater] checkForUpdates failed after retries: ${e?.message || e}`);
1009+
} finally {
1010+
updaterCheckRetrying = false;
1011+
}
1012+
})();
9571013
};
9581014

9591015
// 1) On startup (each app launch)

0 commit comments

Comments
 (0)