mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	feat(installer): retry download if connection is interrupted (#5126)
Fixes #5110
This commit is contained in:
		
							parent
							
								
									b323018881
								
							
						
					
					
						commit
						fe1302b47d
					
				| @ -133,7 +133,18 @@ export async function downloadBrowserWithProgressBar(browsersPath: string, brows | |||||||
|   const url = revisionURL(browser); |   const url = revisionURL(browser); | ||||||
|   const zipPath = path.join(os.tmpdir(), `playwright-download-${browser.name}-${browserPaths.hostPlatform}-${browser.revision}.zip`); |   const zipPath = path.join(os.tmpdir(), `playwright-download-${browser.name}-${browserPaths.hostPlatform}-${browser.revision}.zip`); | ||||||
|   try { |   try { | ||||||
|     await downloadFile(url, zipPath, progress); |     for (let attempt = 1, N = 3; attempt <= N; ++attempt) { | ||||||
|  |       const {error} = await downloadFile(url, zipPath, progress); | ||||||
|  |       if (!error) | ||||||
|  |         break; | ||||||
|  |       if (attempt < N && error && typeof error === 'object' && typeof error.message === 'string' && error.message.includes('ECONNRESET')) { | ||||||
|  |         // Maximum delay is 3rd retry: 1337.5ms
 | ||||||
|  |         const millis = (Math.random() * 200) + (250 * Math.pow(1.5, attempt)); | ||||||
|  |         await new Promise(c => setTimeout(c, millis)); | ||||||
|  |       } else { | ||||||
|  |         throw error; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|     await extract(zipPath, { dir: browserPath}); |     await extract(zipPath, { dir: browserPath}); | ||||||
|     await chmodAsync(browserPaths.executablePath(browserPath, browser)!, 0o755); |     await chmodAsync(browserPaths.executablePath(browserPath, browser)!, 0o755); | ||||||
|   } catch (e) { |   } catch (e) { | ||||||
| @ -152,31 +163,30 @@ function toMegabytes(bytes: number) { | |||||||
|   return `${Math.round(mb * 10) / 10} Mb`; |   return `${Math.round(mb * 10) / 10} Mb`; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function downloadFile(url: string, destinationPath: string, progressCallback: OnProgressCallback | undefined): Promise<any> { | function downloadFile(url: string, destinationPath: string, progressCallback: OnProgressCallback | undefined): Promise<{error: any}> { | ||||||
|   let fulfill: () => void = () => {}; |   let fulfill: ({error}: {error: any}) => void = ({error}) => {}; | ||||||
|   let reject: (error: any) => void = () => {}; |  | ||||||
|   let downloadedBytes = 0; |   let downloadedBytes = 0; | ||||||
|   let totalBytes = 0; |   let totalBytes = 0; | ||||||
| 
 | 
 | ||||||
|   const promise = new Promise((x, y) => { fulfill = x; reject = y; }); |   const promise: Promise<{error: any}> = new Promise(x => { fulfill = x; }); | ||||||
| 
 | 
 | ||||||
|   const request = httpRequest(url, 'GET', response => { |   const request = httpRequest(url, 'GET', response => { | ||||||
|     if (response.statusCode !== 200) { |     if (response.statusCode !== 200) { | ||||||
|       const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`); |       const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`); | ||||||
|       // consume response data to free up memory
 |       // consume response data to free up memory
 | ||||||
|       response.resume(); |       response.resume(); | ||||||
|       reject(error); |       fulfill({error}); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     const file = fs.createWriteStream(destinationPath); |     const file = fs.createWriteStream(destinationPath); | ||||||
|     file.on('finish', () => fulfill()); |     file.on('finish', () => fulfill({error: null})); | ||||||
|     file.on('error', error => reject(error)); |     file.on('error', error => fulfill({error})); | ||||||
|     response.pipe(file); |     response.pipe(file); | ||||||
|     totalBytes = parseInt(response.headers['content-length'], 10); |     totalBytes = parseInt(response.headers['content-length'], 10); | ||||||
|     if (progressCallback) |     if (progressCallback) | ||||||
|       response.on('data', onData); |       response.on('data', onData); | ||||||
|   }); |   }); | ||||||
|   request.on('error', (error: any) => reject(error)); |   request.on('error', (error: any) => fulfill({error})); | ||||||
|   return promise; |   return promise; | ||||||
| 
 | 
 | ||||||
|   function onData(chunk: string) { |   function onData(chunk: string) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Andrey Lushnikov
						Andrey Lushnikov