mirror of
				https://github.com/Swatinem/rust-cache.git
				synced 2025-10-31 23:43:47 +00:00 
			
		
		
		
	Merge ccd52e107768d27a2dd400974a0e2e4cdc7ec278 into 76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e
This commit is contained in:
		
						commit
						9244268a9e
					
				| @ -14,6 +14,12 @@ inputs: | ||||
|   workspaces: | ||||
|     description: "Paths to multiple Cargo workspaces and their target directories, separated by newlines" | ||||
|     required: false | ||||
|   maxRetryAttempts: | ||||
|     description: "The amount of attempts to retry the network operations after retriable errors" | ||||
|     required: false | ||||
|   timeout: | ||||
|     description: "The timeout for the networking operations" | ||||
|     required: false | ||||
|   cache-on-failure: | ||||
|     description: "Cache even if the build fails. Defaults to false" | ||||
|     required: false | ||||
|  | ||||
							
								
								
									
										1033
									
								
								dist/restore/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1033
									
								
								dist/restore/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1063
									
								
								dist/save/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1063
									
								
								dist/save/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -5,6 +5,7 @@ | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "rust-cache", | ||||
|       "version": "2.0.0", | ||||
|       "license": "LGPL-3.0", | ||||
|       "dependencies": { | ||||
|  | ||||
| @ -27,6 +27,11 @@ export class CacheConfig { | ||||
|   /** The workspace configurations */ | ||||
|   public workspaces: Array<Workspace> = []; | ||||
| 
 | ||||
|   /** The max timeout for the networking operations */ | ||||
|   public timeout: null | number = null; | ||||
|   /** The max retry attemtps for the networking operations */ | ||||
|   public maxRetryAttempts: number = 0; | ||||
| 
 | ||||
|   /** The prefix portion of the cache key */ | ||||
|   private keyPrefix = ""; | ||||
|   /** The rust version considered for the cache key */ | ||||
| @ -156,6 +161,12 @@ export class CacheConfig { | ||||
| 
 | ||||
|     self.cachePaths = [CARGO_HOME, ...workspaces.map((ws) => ws.target)]; | ||||
| 
 | ||||
|     const timeoutInput = core.getInput("timeout") | ||||
|     self.timeout = timeoutInput ? parseFloat(timeoutInput) : null; | ||||
| 
 | ||||
|     const maxRetryAttemptsInput = core.getInput("maxRetryAttempts") | ||||
|     self.maxRetryAttempts =  maxRetryAttemptsInput ? parseFloat(maxRetryAttemptsInput) : 0; | ||||
| 
 | ||||
|     return self; | ||||
|   } | ||||
| 
 | ||||
| @ -184,6 +195,10 @@ export class CacheConfig { | ||||
|     for (const file of this.keyFiles) { | ||||
|       core.info(`  - ${file}`); | ||||
|     } | ||||
|     core.info(`Network operations timeout:`); | ||||
|     core.info(`    ${this.timeout}`); | ||||
|     core.info(`Max retry attempts for the network operations:`); | ||||
|     core.info(`    ${this.maxRetryAttempts}`); | ||||
|     core.endGroup(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ import * as core from "@actions/core"; | ||||
| 
 | ||||
| import { cleanTargetDir, getCargoBins } from "./cleanup"; | ||||
| import { CacheConfig, STATE_BINS, STATE_KEY } from "./config"; | ||||
| import { withRetries, withTimeout } from "./utils"; | ||||
| 
 | ||||
| process.on("uncaughtException", (e) => { | ||||
|   core.info(`[warning] ${e.message}`); | ||||
| @ -34,7 +35,16 @@ async function run() { | ||||
| 
 | ||||
|     core.info(`... Restoring cache ...`); | ||||
|     const key = config.cacheKey; | ||||
|     const restoreKey = await cache.restoreCache(config.cachePaths, key, [config.restoreKey]); | ||||
|     const restoreKey = await withRetries( | ||||
|       () => | ||||
|         withTimeout( | ||||
|           () => cache.restoreCache(config.cachePaths, key, [config.restoreKey]), | ||||
|           config.timeout | ||||
|         ), | ||||
|       config.maxRetryAttempts, | ||||
|       () => true | ||||
|     ); | ||||
| 
 | ||||
|     if (restoreKey) { | ||||
|       core.info(`Restored from cache key "${restoreKey}".`); | ||||
|       core.saveState(STATE_KEY, restoreKey); | ||||
|  | ||||
							
								
								
									
										11
									
								
								src/save.ts
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/save.ts
									
									
									
									
									
								
							| @ -4,6 +4,7 @@ import * as exec from "@actions/exec"; | ||||
| 
 | ||||
| import { cleanBin, cleanGit, cleanRegistry, cleanTargetDir } from "./cleanup"; | ||||
| import { CacheConfig, STATE_KEY } from "./config"; | ||||
| import { withRetries, withTimeout } from "./utils"; | ||||
| 
 | ||||
| process.on("uncaughtException", (e) => { | ||||
|   core.info(`[warning] ${e.message}`); | ||||
| @ -64,7 +65,15 @@ async function run() { | ||||
|     } | ||||
| 
 | ||||
|     core.info(`... Saving cache ...`); | ||||
|     await cache.saveCache(config.cachePaths, config.cacheKey); | ||||
|     await withRetries( | ||||
|       () => | ||||
|         withTimeout( | ||||
|           () => cache.saveCache(config.cachePaths, config.cacheKey), | ||||
|           config.timeout | ||||
|         ), | ||||
|       config.maxRetryAttempts, | ||||
|       () => true | ||||
|     ); | ||||
|   } catch (e) { | ||||
|     core.info(`[warning] ${(e as any).stack}`); | ||||
|   } | ||||
|  | ||||
							
								
								
									
										46
									
								
								src/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/utils.ts
									
									
									
									
									
								
							| @ -28,3 +28,49 @@ export async function getCmdOutput( | ||||
|   } | ||||
|   return stdout; | ||||
| } | ||||
| 
 | ||||
| export async function withRetries<T>( | ||||
|   operation: () => Promise<T>, | ||||
|   maxRetryAttempts: number, | ||||
|   isRetriable: (error: unknown) => boolean | ||||
| ): Promise<T> { | ||||
|   let attemptsLeft = maxRetryAttempts; | ||||
|   while (true) { | ||||
|     try { | ||||
|       return await operation(); | ||||
|     } catch (e: unknown) { | ||||
|       attemptsLeft -= 1; | ||||
|       if (attemptsLeft <= 0) { | ||||
|         throw e; | ||||
|       } | ||||
|       if (!isRetriable(e)) { | ||||
|         throw e; | ||||
|       } | ||||
|       core.info( | ||||
|         `[warning] Retrying after an error, ${attemptsLeft} attempts left, error: ${e}` | ||||
|       ); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class TimeoutError extends Error {} | ||||
| 
 | ||||
| export async function withTimeout<T>( | ||||
|   operation: (onTimeout: Promise<void>) => Promise<T>, | ||||
|   timeoutMs: null | number | ||||
| ): Promise<T> { | ||||
|   const timeout = timeoutMs | ||||
|     ? new Promise<void>((resolve) => { | ||||
|         setTimeout(resolve, timeoutMs); | ||||
|       }) | ||||
|     : new Promise<never>(() => {}); | ||||
| 
 | ||||
|   const timeoutSym = Symbol("timeout" as const); | ||||
|   const racingTimeout = timeout.then(() => timeoutSym); | ||||
| 
 | ||||
|   const result = await Promise.race([racingTimeout, operation(timeout)]); | ||||
|   if (result === timeoutSym) { | ||||
|     throw new TimeoutError("operation timeout"); | ||||
|   } | ||||
|   return result as Awaited<T>; | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user