@@ -17,6 +17,46 @@ import {ContextInfo} from '@docker/actions-toolkit/lib/types/docker/docker';
1717import * as context from './context' ;
1818import * as stateHelper from './state-helper' ;
1919
20+ /**
21+ * Retry a function with exponential backoff
22+ */
23+ async function retryWithBackoff < T > (
24+ operation : ( ) => Promise < T > ,
25+ maxRetries : number = 3 ,
26+ initialDelay : number = 1000 ,
27+ maxDelay : number = 10000 ,
28+ shouldRetry : ( error : Error ) => boolean = ( ) => true
29+ ) : Promise < T > {
30+ let retries = 0 ;
31+ let delay = initialDelay ;
32+
33+ while ( true ) {
34+ try {
35+ return await operation ( ) ;
36+ } catch ( error ) {
37+ if ( retries >= maxRetries || ! shouldRetry ( error ) ) {
38+ throw error ;
39+ }
40+
41+ retries ++ ;
42+ core . info ( `Retry ${ retries } /${ maxRetries } after ${ delay } ms due to: ${ error . message } ` ) ;
43+ await new Promise ( resolve => setTimeout ( resolve , delay ) ) ;
44+
45+ // Exponential backoff with jitter
46+ delay = Math . min ( delay * 2 , maxDelay ) * ( 0.8 + Math . random ( ) * 0.4 ) ;
47+ }
48+ }
49+ }
50+
51+ /**
52+ * Check if an error is a buildkit socket connection error
53+ */
54+ function isBuildkitSocketError ( error : Error ) : boolean {
55+ return error . message . includes ( '/run/buildkit/buildkitd.sock' ) ||
56+ error . message . includes ( 'failed to list workers' ) ||
57+ error . message . includes ( 'connection error' ) ;
58+ }
59+
2060actionsToolkit . run (
2161 // main
2262 async ( ) => {
@@ -165,13 +205,29 @@ actionsToolkit.run(
165205
166206 await core . group ( `Booting builder` , async ( ) => {
167207 const inspectCmd = await toolkit . buildx . getCommand ( await context . getInspectArgs ( inputs , toolkit ) ) ;
168- await Exec . getExecOutput ( inspectCmd . command , inspectCmd . args , {
169- ignoreReturnCode : true
170- } ) . then ( res => {
171- if ( res . stderr . length > 0 && res . exitCode != 0 ) {
172- throw new Error ( res . stderr . match ( / ( .* ) \s * $ / ) ?. [ 0 ] ?. trim ( ) ?? 'unknown error' ) ;
173- }
174- } ) ;
208+
209+ try {
210+ await retryWithBackoff (
211+ async ( ) => {
212+ const res = await Exec . getExecOutput ( inspectCmd . command , inspectCmd . args , {
213+ ignoreReturnCode : true
214+ } ) ;
215+
216+ if ( res . stderr . length > 0 && res . exitCode != 0 ) {
217+ throw new Error ( res . stderr . match ( / ( .* ) \s * $ / ) ?. [ 0 ] ?. trim ( ) ?? 'unknown error' ) ;
218+ }
219+ return res ;
220+ } ,
221+ 5 , // maxRetries - retry up to 5 times for buildkit initialization
222+ 1000 , // initialDelay - start with 1 second
223+ 15000 , // maxDelay - cap at 15 seconds
224+ isBuildkitSocketError // only retry on buildkit socket errors
225+ ) ;
226+ } catch ( error ) {
227+ // Log the warning but continue - this matches current behavior where builds still succeed
228+ core . warning ( `Failed to bootstrap builder after multiple retries: ${ error . message } ` ) ;
229+ core . warning ( 'Continuing execution as buildkit daemon may initialize later' ) ;
230+ }
175231 } ) ;
176232
177233 if ( inputs . install ) {
0 commit comments