From b5a44161a4b2af3bf6b08970d3f8fc151ee1796a Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Wed, 11 May 2016 09:52:35 -0700 Subject: [PATCH] cmd/pull: add retry to curl bottle download (#232) Works around issue with GET and HEAD apparently acting differently, and bottle downloads failing even after successful polling completion. --- Library/Homebrew/cmd/pull.rb | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/Library/Homebrew/cmd/pull.rb b/Library/Homebrew/cmd/pull.rb index 815ae60a4d..be1d331a8a 100644 --- a/Library/Homebrew/cmd/pull.rb +++ b/Library/Homebrew/cmd/pull.rb @@ -514,37 +514,57 @@ module Homebrew next end - # Poll for publication completion using a quick HEAD, to avoid spurious error messages + # Poll for publication completion using a quick partial HEAD, to avoid spurious error messages # 401 error is normal while file is still in async publishing process url = URI(bottle_info.url) puts "Verifying bottle: #{File.basename(url.path)}" http = Net::HTTP.new(url.host, url.port) http.use_ssl = true + retry_count = 0 http.start do while true do req = Net::HTTP::Head.new bottle_info.url res = http.request req - retry_count += 1 if res.is_a?(Net::HTTPSuccess) break elsif res.is_a?(Net::HTTPClientError) if retry_count >= max_retries - raise "Failed to download #{f} bottle from #{url}!" + raise "Failed to find published #{f} bottle at #{url}!" end print(wrote_dots ? "." : "Waiting on Bintray.") wrote_dots = true sleep poll_retry_delay_seconds + retry_count += 1 else - raise "Failed to download #{f} bottle from #{url} (#{res.code} #{res.message})!" + raise "Failed to find published #{f} bottle at #{url} (#{res.code} #{res.message})!" end end end # Actual download and verification + # We do a retry on this, too, because sometimes the external curl will fail even + # when the prior HEAD has succeeded. puts "\n" if wrote_dots filename = File.basename(url.path) + curl_retry_delay_seconds = 4 + max_curl_retries = 1 + retry_count = 0 # We're in the cache; make sure to force re-download - curl url, "-o", filename + while true do + begin + retry_count + curl url, "-o", filename + break + rescue + if retry_count >= max_curl_retries + raise "Failed to download #{f} bottle from #{url}!" + end + puts "curl download failed; retrying in #{curl_retry_delay_seconds} sec" + sleep curl_retry_delay_seconds + curl_retry_delay_seconds *= 2 + retry_count += 1 + end + end checksum = Checksum.new(:sha256, bottle_info.sha256) Pathname.new(filename).verify_checksum(checksum) end