lib/vagrant-skytap/api/client.rb in vagrant-skytap-0.3.1 vs lib/vagrant-skytap/api/client.rb in vagrant-skytap-0.3.2

- old
+ new

@@ -20,19 +20,21 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. require 'base64' require "vagrant-skytap/version" +require 'timeout' module VagrantPlugins module Skytap module API class Client attr_reader :config, :http + DEFAULT_TIMEOUT = 120 MAX_RATE_LIMIT_RETRIES = 3 - DEFAULT_RETRY_AFTER_SECONDS = 10 + DEFAULT_RETRY_AFTER_SECONDS = 5 def initialize(config) @logger = Log4r::Logger.new("vagrant_skytap::api_client") @config = config @@ -81,38 +83,50 @@ if (query = [uri.query, extra_query].compact.join('&')).present? path = [uri.path, query].join('?') end headers = default_headers.merge(options[:extra_headers] || {}) - tries = 0 retry_after = DEFAULT_RETRY_AFTER_SECONDS + most_recent_exception = nil + begin - tries += 1 - http.send_request(method, URI.encode(path), body, headers).tap do |ret| - @logger.debug("REST API response: #{ret.body}") - unless ret.code =~ /^2\d\d/ - raise Errors::DoesNotExist, object_name: "Object '#{path}'" if ret.code == '404' - error_class = case ret.code - when '403' - Errors::Unauthorized - when '422' - Errors::UnprocessableEntity - when '423' - Errors::ResourceBusy - when '429' - retry_after = ret['Retry-After'] || DEFAULT_RETRY_AFTER_SECONDS - Errors::RateLimited - else - Errors::OperationFailed + Timeout.timeout(options[:timeout] || DEFAULT_TIMEOUT) do + begin + http.send_request(method, URI.encode(path), body, headers).tap do |ret| + @logger.debug("REST API response: #{ret.body}") + unless ret.code =~ /^2\d\d/ + raise Errors::DoesNotExist, object_name: "Object '#{path}'" if ret.code == '404' + error_class = case ret.code + when '403' + Errors::Unauthorized + when '422' + Errors::UnprocessableEntity + when '423' + Errors::ResourceBusy + when '429' + retry_after = ret['Retry-After'] || DEFAULT_RETRY_AFTER_SECONDS + Errors::RateLimited + else + Errors::OperationFailed + end + raise error_class, err: error_string_from_body(ret) + end end - raise error_class, err: error_string_from_body(ret) + rescue Errors::RateLimited => ex + most_recent_exception = ex + @logger.info("Rate limited, wil retry in #{retry_after} seconds") + sleep retry_after.to_f + 0.1 + retry + rescue Errors::ResourceBusy => ex + most_recent_exception = ex + @logger.debug("Resource busy, retrying") + sleep DEFAULT_RETRY_AFTER_SECONDS + retry end end - rescue Errors::RateLimited => ex - raise if tries > MAX_RATE_LIMIT_RETRIES - @logger.info("Rate limited, wil retry in #{retry_after} seconds") - sleep retry_after.to_f + 0.1 - retry + rescue Timeout::Error => ex + raise most_recent_exception if most_recent_exception + raise Errors::OperationFailed, "Timeout exceeded" end end def error_string_from_body(resp) resp = resp.body if resp.respond_to?(:body)