Skip to content

Commit bc426c0

Browse files
committed
fix(content.config.ts): add fetch retry with exponential backoff
Handle failed fetch's.
1 parent 10c8607 commit bc426c0

File tree

1 file changed

+54
-68
lines changed

1 file changed

+54
-68
lines changed

src/content.config.ts

Lines changed: 54 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,7 @@ async function generateArticleArchive(
118118
` Downloading thumbnail from ${pageData.frontmatter.thumbnail}`
119119
);
120120

121-
const controller = new AbortController();
122-
const timeoutId = setTimeout(() => controller.abort(), 30000);
123-
124-
const response = await fetch(pageData.frontmatter.thumbnail, {
125-
signal: controller.signal,
126-
});
127-
128-
clearTimeout(timeoutId);
121+
const response = await fetchWithRetry(pageData.frontmatter.thumbnail);
129122

130123
if (response.ok) {
131124
const buffer = await response.arrayBuffer();
@@ -158,14 +151,7 @@ async function generateArticleArchive(
158151
` Downloading ${download.filename} from ${download.url}`
159152
);
160153

161-
const controller = new AbortController();
162-
const timeoutId = setTimeout(() => controller.abort(), 30000);
163-
164-
const response = await fetch(download.url, {
165-
signal: controller.signal,
166-
});
167-
168-
clearTimeout(timeoutId);
154+
const response = await fetchWithRetry(download.url);
169155

170156
if (response.ok) {
171157
const buffer = await response.arrayBuffer();
@@ -261,6 +247,50 @@ function getArticlesFromConfig(
261247
}
262248
}
263249

250+
/**
251+
* Fetch with retry logic
252+
*/
253+
async function fetchWithRetry(
254+
url: string,
255+
options: RequestInit = {},
256+
maxRetries: number = 3,
257+
timeout: number = 60000
258+
): Promise<Response> {
259+
let lastError: Error | null = null;
260+
261+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
262+
try {
263+
const controller = new AbortController();
264+
const timeoutId = setTimeout(() => controller.abort(), timeout);
265+
266+
const response = await fetch(url, {
267+
...options,
268+
signal: controller.signal,
269+
});
270+
271+
clearTimeout(timeoutId);
272+
return response;
273+
} catch (error) {
274+
lastError = error as Error;
275+
console.warn(
276+
`Fetch attempt ${attempt}/${maxRetries} failed for ${url}:`,
277+
error
278+
);
279+
280+
if (attempt < maxRetries) {
281+
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
282+
console.log(`Retrying in ${delay}ms...`);
283+
await new Promise((resolve) => setTimeout(resolve, delay));
284+
}
285+
}
286+
}
287+
288+
throw (
289+
lastError ||
290+
new Error(`Failed to fetch ${url} after ${maxRetries} attempts`)
291+
);
292+
}
293+
264294
/**
265295
* Fetch all article IDs from myst.xref.json
266296
*/
@@ -269,14 +299,7 @@ async function getAllArticles(baseUrl: string): Promise<number[]> {
269299
const xrefUrl = `${baseUrl}/myst.xref.json`;
270300
console.log(`Fetching all articles from ${xrefUrl}`);
271301

272-
const controller = new AbortController();
273-
const timeoutId = setTimeout(() => controller.abort(), 10000);
274-
275-
const response = await fetch(xrefUrl, {
276-
signal: controller.signal,
277-
});
278-
279-
clearTimeout(timeoutId);
302+
const response = await fetchWithRetry(xrefUrl);
280303

281304
if (!response.ok) {
282305
console.warn(`Failed to fetch myst.xref.json: ${response.status}`);
@@ -346,18 +369,10 @@ const createFilteredPagesLoader = (
346369
`Fetching article ${articleId} from https://dev-beta.dpid.org/${articleId}?format=myst`
347370
);
348371

349-
const controller = new AbortController();
350-
const timeoutId = setTimeout(() => controller.abort(), 10000);
351-
352-
const response = await fetch(
353-
`https://dev-beta.dpid.org/${articleId}?format=myst`,
354-
{
355-
signal: controller.signal,
356-
}
372+
const response = await fetchWithRetry(
373+
`https://dev-beta.dpid.org/${articleId}?format=myst`
357374
);
358375

359-
clearTimeout(timeoutId);
360-
361376
if (!response.ok) {
362377
console.warn(
363378
`Failed to fetch article ${articleId}: ${response.status}`
@@ -447,17 +462,7 @@ const createFilteredPagesLoader = (
447462
`Downloading article.pdf for ${insightJournalId} from ${articlePdfDownload.url}`
448463
);
449464

450-
const pdfController = new AbortController();
451-
const pdfTimeoutId = setTimeout(
452-
() => pdfController.abort(),
453-
30000
454-
);
455-
456-
const pdfResponse = await fetch(articlePdfDownload.url, {
457-
signal: pdfController.signal,
458-
});
459-
460-
clearTimeout(pdfTimeoutId);
465+
const pdfResponse = await fetchWithRetry(articlePdfDownload.url);
461466

462467
if (pdfResponse.ok) {
463468
const pdfBuffer = await pdfResponse.arrayBuffer();
@@ -497,18 +502,10 @@ const createFilteredPagesLoader = (
497502
`Fetching insight-journal-metadata.json for ${insightJournalId} from ${metadataDownload.url}`
498503
);
499504

500-
const metadataController = new AbortController();
501-
const metadataTimeoutId = setTimeout(
502-
() => metadataController.abort(),
503-
10000
505+
const metadataResponse = await fetchWithRetry(
506+
metadataDownload.url
504507
);
505508

506-
const metadataResponse = await fetch(metadataDownload.url, {
507-
signal: metadataController.signal,
508-
});
509-
510-
clearTimeout(metadataTimeoutId);
511-
512509
if (metadataResponse.ok) {
513510
const metadataJson = await metadataResponse.json();
514511
console.log(
@@ -582,21 +579,10 @@ const createFilteredPagesLoader = (
582579
`Downloading thumbnail for ${insightJournalId} from ${pageData.frontmatter.thumbnail}`
583580
);
584581

585-
const thumbnailController = new AbortController();
586-
const thumbnailTimeoutId = setTimeout(
587-
() => thumbnailController.abort(),
588-
30000
582+
const thumbnailResponse = await fetchWithRetry(
583+
pageData.frontmatter.thumbnail
589584
);
590585

591-
const thumbnailResponse = await fetch(
592-
pageData.frontmatter.thumbnail,
593-
{
594-
signal: thumbnailController.signal,
595-
}
596-
);
597-
598-
clearTimeout(thumbnailTimeoutId);
599-
600586
if (thumbnailResponse.ok) {
601587
const thumbnailBuffer = await thumbnailResponse.arrayBuffer();
602588
const thumbnailsDir = join(publicDir, "thumbnails");

0 commit comments

Comments
 (0)