mirror of
				https://github.com/docker/setup-buildx-action.git
				synced 2025-11-01 01:40:11 +08:00 
			
		
		
		
	Add retry mechanism with exponential backoff for buildkit bootstrap
Signed-off-by: Daniel Amar <daniel.amar@onepeloton.com>
This commit is contained in:
		
							parent
							
								
									e600775e52
								
							
						
					
					
						commit
						bc3c5abd64
					
				
							
								
								
									
										70
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								src/main.ts
									
									
									
									
									
								
							| @ -17,6 +17,46 @@ import {ContextInfo} from '@docker/actions-toolkit/lib/types/docker/docker'; | |||||||
| import * as context from './context'; | import * as context from './context'; | ||||||
| import * as stateHelper from './state-helper'; | import * as stateHelper from './state-helper'; | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Retry a function with exponential backoff | ||||||
|  |  */ | ||||||
|  | async function retryWithBackoff<T>( | ||||||
|  |   operation: () => Promise<T>, | ||||||
|  |   maxRetries: number = 3, | ||||||
|  |   initialDelay: number = 1000, | ||||||
|  |   maxDelay: number = 10000, | ||||||
|  |   shouldRetry: (error: Error) => boolean = () => true | ||||||
|  | ): Promise<T> { | ||||||
|  |   let retries = 0; | ||||||
|  |   let delay = initialDelay; | ||||||
|  |    | ||||||
|  |   while (true) { | ||||||
|  |     try { | ||||||
|  |       return await operation(); | ||||||
|  |     } catch (error) { | ||||||
|  |       if (retries >= maxRetries || !shouldRetry(error)) { | ||||||
|  |         throw error; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       retries++; | ||||||
|  |       core.info(`Retry ${retries}/${maxRetries} after ${delay}ms due to: ${error.message}`); | ||||||
|  |       await new Promise(resolve => setTimeout(resolve, delay)); | ||||||
|  |        | ||||||
|  |       // Exponential backoff with jitter
 | ||||||
|  |       delay = Math.min(delay * 2, maxDelay) * (0.8 + Math.random() * 0.4); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Check if an error is a buildkit socket connection error | ||||||
|  |  */ | ||||||
|  | function isBuildkitSocketError(error: Error): boolean { | ||||||
|  |   return error.message.includes('/run/buildkit/buildkitd.sock') ||  | ||||||
|  |          error.message.includes('failed to list workers') || | ||||||
|  |          error.message.includes('connection error'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| actionsToolkit.run( | actionsToolkit.run( | ||||||
|   // main
 |   // main
 | ||||||
|   async () => { |   async () => { | ||||||
| @ -165,13 +205,29 @@ actionsToolkit.run( | |||||||
| 
 | 
 | ||||||
|     await core.group(`Booting builder`, async () => { |     await core.group(`Booting builder`, async () => { | ||||||
|       const inspectCmd = await toolkit.buildx.getCommand(await context.getInspectArgs(inputs, toolkit)); |       const inspectCmd = await toolkit.buildx.getCommand(await context.getInspectArgs(inputs, toolkit)); | ||||||
|       await Exec.getExecOutput(inspectCmd.command, inspectCmd.args, { |        | ||||||
|         ignoreReturnCode: true |       try { | ||||||
|       }).then(res => { |         await retryWithBackoff( | ||||||
|         if (res.stderr.length > 0 && res.exitCode != 0) { |           async () => { | ||||||
|           throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'); |             const res = await Exec.getExecOutput(inspectCmd.command, inspectCmd.args, { | ||||||
|         } |               ignoreReturnCode: true | ||||||
|       }); |             }); | ||||||
|  |              | ||||||
|  |             if (res.stderr.length > 0 && res.exitCode != 0) { | ||||||
|  |               throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'); | ||||||
|  |             } | ||||||
|  |             return res; | ||||||
|  |           }, | ||||||
|  |           5,  // maxRetries - retry up to 5 times for buildkit initialization
 | ||||||
|  |           1000,  // initialDelay - start with 1 second
 | ||||||
|  |           15000,  // maxDelay - cap at 15 seconds
 | ||||||
|  |           isBuildkitSocketError  // only retry on buildkit socket errors
 | ||||||
|  |         ); | ||||||
|  |       } catch (error) { | ||||||
|  |         // Log the warning but continue - this matches current behavior where builds still succeed
 | ||||||
|  |         core.warning(`Failed to bootstrap builder after multiple retries: ${error.message}`); | ||||||
|  |         core.warning('Continuing execution as buildkit daemon may initialize later'); | ||||||
|  |       } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     if (inputs.install) { |     if (inputs.install) { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Daniel Amar
						Daniel Amar