@@ -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