@@ -68,7 +68,7 @@ import { applyDefaults } from "../util/data.js";
6868import { calculateFileSizeAndHash } from "../util/hash.js" ;
6969import { getFiles } from "../util/files.js" ;
7070import { generateOrLoadPublishId } from "../util/publish-id.js" ;
71- import { FastlyApiContext , loadApiKey } from "../util/fastly-api.js" ;
71+ import { FastlyApiContext , FetchError , loadApiKey } from "../util/fastly-api.js" ;
7272import { kvStoreEntryExists , kvStoreSubmitFile } from "../util/kv-store.js" ;
7373import { mergeContentTypes , testFileContentType } from "../../util/content-types.js" ;
7474import { algs } from "../compression/index.js" ;
@@ -94,6 +94,9 @@ import type {
9494 ContentFileInfoForWasmInline ,
9595 ContentFileInfoForKVStore ,
9696} from "../../types/content-assets.js" ;
97+ import {
98+ attemptWithRetries ,
99+ } from "../util/retryable.js" ;
97100
98101type AssetInfo =
99102 ContentTypeTestResult &
@@ -123,17 +126,54 @@ type KVStoreItemDesc = {
123126} ;
124127
125128async function uploadFilesToKVStore ( fastlyApiContext : FastlyApiContext , kvStoreName : string , kvStoreItems : KVStoreItemDesc [ ] ) {
126- for ( const { kvStoreKey, staticFilePath, text } of kvStoreItems ) {
127- if ( await kvStoreEntryExists ( fastlyApiContext , kvStoreName , kvStoreKey ) ) {
128- // Already exists in KV Store
129- console . log ( `✔️ Asset already exists in KV Store with key "${ kvStoreKey } ".` )
130- } else {
131- // Upload to KV Store
132- const fileData = fs . readFileSync ( staticFilePath ) ;
133- await kvStoreSubmitFile ( fastlyApiContext ! , kvStoreName ! , kvStoreKey , fileData ) ;
134- console . log ( `✔️ Submitted ${ text ? 'text' : 'binary' } asset "${ staticFilePath } " to KV Store with key "${ kvStoreKey } ".` )
129+
130+ const maxConcurrent = 12 ;
131+ let index = 0 ; // Shared among workers
132+
133+ async function worker ( ) {
134+ while ( index < kvStoreItems . length ) {
135+ const currentIndex = index ;
136+ index = index + 1 ;
137+ const { kvStoreKey, staticFilePath, text } = kvStoreItems [ currentIndex ] ;
138+
139+ try {
140+ await attemptWithRetries (
141+ async ( ) => {
142+ if ( await kvStoreEntryExists ( fastlyApiContext , kvStoreName , kvStoreKey ) ) {
143+ console . log ( `✔️ Asset already exists in KV Store with key "${ kvStoreKey } ".` ) ;
144+ return ;
145+ }
146+ const fileData = fs . readFileSync ( staticFilePath ) ;
147+ await kvStoreSubmitFile ( fastlyApiContext , kvStoreName , kvStoreKey , fileData ) ;
148+ console . log ( `✔️ Submitted ${ text ? 'text' : 'binary' } asset "${ staticFilePath } " to KV Store with key "${ kvStoreKey } ".` )
149+ } ,
150+ {
151+ onAttempt ( attempt ) {
152+ if ( attempt > 0 ) {
153+ console . log ( `Attempt ${ attempt + 1 } for: ${ kvStoreKey } ` ) ;
154+ }
155+ } ,
156+ onRetry ( attempt , err , delay ) {
157+ let statusMessage = 'unknown' ;
158+ if ( err instanceof FetchError ) {
159+ statusMessage = `HTTP ${ err . status } ` ;
160+ } else if ( err instanceof TypeError ) {
161+ statusMessage = 'transport' ;
162+ }
163+ console . log ( `Attempt ${ attempt + 1 } for ${ kvStoreKey } gave retryable error (${ statusMessage } ), delaying ${ delay } ms` ) ;
164+ } ,
165+ }
166+ ) ;
167+ } catch ( err ) {
168+ const e = err instanceof Error ? err : new Error ( String ( err ) ) ;
169+ console . error ( `❌ Failed: ${ kvStoreKey } → ${ e . message } ` ) ;
170+ console . error ( e . stack ) ;
171+ }
135172 }
136173 }
174+
175+ const workers = Array . from ( { length : maxConcurrent } , ( ) => worker ( ) ) ;
176+ await Promise . all ( workers ) ;
137177}
138178
139179function writeKVStoreEntriesToFastlyToml ( kvStoreName : string , kvStoreItems : KVStoreItemDesc [ ] ) {
@@ -154,7 +194,7 @@ function writeKVStoreEntriesToFastlyToml(kvStoreName: string, kvStoreItems: KVSt
154194
155195 if ( fastlyToml . indexOf ( kvStoreName ) !== - 1 ) {
156196 // don't do this!
157- console . error ( " improperly configured entry for '${kvStoreName}' in fastly.toml" ) ;
197+ console . error ( ` improperly configured entry for '${ kvStoreName } ' in fastly.toml` ) ;
158198 // TODO: handle thrown exception from callers
159199 throw "No" !
160200 }
0 commit comments