def retriable_rest_request(method, url, req_body, headers)
rest_request = Chef::REST::RESTRequest.new(method, url, req_body, headers)
Chef::Log.debug("Sending HTTP Request via #{method} to #{url.host}:#{url.port}#{rest_request.path}")
http_attempts = 0
begin
http_attempts += 1
res = yield rest_request
rescue SocketError, Errno::ETIMEDOUT => e
e.message.replace "Error connecting to #{url} - #{e.message}"
raise e
rescue Errno::ECONNREFUSED
if http_retry_count - http_attempts + 1 > 0
Chef::Log.error("Connection refused connecting to #{url.host}:#{url.port} for #{rest_request.path}, retry #{http_attempts}/#{http_retry_count}")
sleep(http_retry_delay)
retry
end
raise Errno::ECONNREFUSED, "Connection refused connecting to #{url.host}:#{url.port} for #{rest_request.path}, giving up"
rescue Timeout::Error
if http_retry_count - http_attempts + 1 > 0
Chef::Log.error("Timeout connecting to #{url.host}:#{url.port} for #{rest_request.path}, retry #{http_attempts}/#{http_retry_count}")
sleep(http_retry_delay)
retry
end
raise Timeout::Error, "Timeout connecting to #{url.host}:#{url.port} for #{rest_request.path}, giving up"
rescue Net::HTTPFatalError => e
if http_retry_count - http_attempts + 1 > 0
sleep_time = 1 + (2 ** http_attempts) + rand(2 ** http_attempts)
Chef::Log.error("Server returned error for #{url}, retrying #{http_attempts}/#{http_retry_count} in #{sleep_time}s")
sleep(sleep_time)
retry
end
raise
end
end