Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

api calls now get retried #2561

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
70 changes: 40 additions & 30 deletions lib/bundler/fetcher.rb
Expand Up @@ -4,11 +4,6 @@ module Bundler

# Handles all the fetching with the rubygems server
class Fetcher
# How many redirects to allew in one request
REDIRECT_LIMIT = 5
# how long to wait for each gemcutter API call
API_TIMEOUT = 10

# This error is raised if the API returns a 413 (only printed in verbose)
class FallbackError < HTTPError; end
# This is the error raised if OpenSSL fails the cert verification
Expand All @@ -33,7 +28,7 @@ def initialize(msg = nil)
end

class << self
attr_accessor :disable_endpoint
attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries

@@spec_fetch_map ||= {}

Expand Down Expand Up @@ -65,6 +60,13 @@ def download_gem_from_uri(spec, uri)
end

def initialize(remote_uri)
# How many redirects to allew in one request
@redirect_limit = 5
# How long to wait for each gemcutter API call
@api_timeout = 10
# How many retries for the gemcutter API call
@max_retries = 3

@remote_uri = remote_uri
@public_uri = remote_uri.dup
@public_uri.user, @public_uri.password = nil, nil # don't print these
Expand All @@ -77,7 +79,7 @@ def initialize(remote_uri)
raise SSLError if @remote_uri.scheme == "https"
@connection = Net::HTTP.new(@remote_uri.host, @remote_uri.port)
end
@connection.read_timeout = API_TIMEOUT
@connection.read_timeout = @api_timeout

Socket.do_not_reverse_lookup = true
end
Expand Down Expand Up @@ -148,35 +150,43 @@ def specs(gem_names, source)

# fetch index
def fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = [])
query_list = gem_names - full_dependency_list
current_retries = 0
begin
query_list = gem_names - full_dependency_list

# only display the message on the first run
if Bundler.ui.debug?
Bundler.ui.debug "Query List: #{query_list.inspect}"
else
Bundler.ui.info ".", false
end
# only display the message on the first run
if Bundler.ui.debug?
Bundler.ui.debug "Query List: #{query_list.inspect}"
else
Bundler.ui.info ".", false
end

return {@remote_uri => last_spec_list} if query_list.empty?
return {@remote_uri => last_spec_list} if query_list.empty?

spec_list, deps_list = fetch_dependency_remote_specs(query_list)
returned_gems = spec_list.map {|spec| spec.first }.uniq
spec_list, deps_list = fetch_dependency_remote_specs(query_list)
returned_gems = spec_list.map {|spec| spec.first }.uniq

fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
# fall back to the legacy index in the following cases
# 1. Gemcutter Endpoint doesn't return a 200
# 2. Marshal blob doesn't load properly
# 3. One of the YAML gemspecs has the Syck::DefaultKey problem
rescue HTTPError, MarshalError, GemspecError => e
@use_api = false
fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
# fall back to the legacy index in the following cases
# 1. Gemcutter Endpoint doesn't return a 200
# 2. Marshal blob doesn't load properly
# 3. One of the YAML gemspecs has the Syck::DefaultKey problem
rescue HTTPError, MarshalError, GemspecError => e

# new line now that the dots are over
Bundler.ui.info "" unless Bundler.ui.debug?

# new line now that the dots are over
Bundler.ui.info "" unless Bundler.ui.debug?
Bundler.ui.debug "Error during API request. #{e.class}: #{e.message}"
Bundler.ui.debug e.backtrace.join(" ")

Bundler.ui.debug "Error during API request. #{e.class}: #{e.message}"
Bundler.ui.debug e.backtrace.join(" ")
if current_retries < @max_retries
current_retries += 1
retry
end

return nil
@use_api = false
return nil
end
end

def use_api
Expand Down Expand Up @@ -205,7 +215,7 @@ def inspect
HTTP_ERRORS << Net::HTTP::Persistent::Error if defined?(Net::HTTP::Persistent)

def fetch(uri, counter = 0)
raise HTTPError, "Too many redirects" if counter >= REDIRECT_LIMIT
raise HTTPError, "Too many redirects" if counter >= @redirect_limit

begin
Bundler.ui.debug "Fetching from: #{uri}"
Expand Down
2 changes: 1 addition & 1 deletion spec/realworld/dependency_api_spec.rb
Expand Up @@ -48,7 +48,7 @@ def wait_for_server(port, seconds = 15)
gem "rack"

old_v, $VERBOSE = $VERBOSE, nil
Bundler::Fetcher::API_TIMEOUT = 1
Bundler::Fetcher.api_timeout = 1
$VERBOSE = old_v
G

Expand Down