Search code examples
rubytimeoutlibcurlcurb

Ruby curb (libcurl): testing for time-out in GET request


Using curb gem (https://github.com/taf2/curb) to GET from a REST API.

  resp = Curl.get("http://someurl.com/users.json") do |http|
    http.headers["API-Key"] = ENV["API_KEY"]
  end
  # do stuff with resp.body_str

I've started encountering occasional time-outs with the Curl.get.

Would like to add logic where I try to GET: if the request times out, we try it again, i.e.

loop do
  resp = Curl.get("http://someurl.com/users.json") do |http|
    http.headers["API-Key"] = ENV["API_KEY"]
  end

  # test result of Curl.get
  # if time-out, then then try again
end

Haven't been able to find/figure out how to test for a time-out result.

What am I missing?

UPDATED: added exception details

Curl::Err::TimeoutError: Timeout was reached
/app/vendor/bundle/ruby/2.3.0/gems/curb-0.9.3/lib/curl/easy.rb:73:in `perform'
/app/vendor/bundle/ruby/2.3.0/gems/curb-0.9.3/lib/curl.rb:17:in `http'
/app/vendor/bundle/ruby/2.3.0/gems/curb-0.9.3/lib/curl.rb:17:in `http'
/app/vendor/bundle/ruby/2.3.0/gems/curb-0.9.3/lib/curl.rb:22:in `get'
/app/lib/tasks/redmine.rake:307:in `block (4 levels) in <top (required)>'

Solution

  • Here is the general idea of the rescue approach I mentioned in my comment:

    loop do
      begin
        resp = Curl.get("http://someurl.com/users.json") do |http|
            http.headers["API-Key"] = ENV["API_KEY"]
        end
        # process successful response here
      rescue Curl::Err::TimeoutError
          # process error here
      end
    end
    

    You would then need to modify this to do the retries. Here is 1 implementation (not tested though):

    # Returns the response on success, nil on TimeoutError
    def get1(url)
      begin
        Curl.get(url) do |http|
          http.headers["API-Key"] = ENV["API_KEY"]
        end
      rescue Curl::Err::TimeoutError
        nil
      end
    end
    
    
    # Returns the response on success, nil on TimeoutErrors after all retry_count attempts.
    def get_with_retries(url, retry_count)
      retry_count.times do
        result = get1(url)
        return result if result
      end
      nil
    end
    
    
    response = get_with_retries("http://someurl.com/users.json", 3)
    if response
      # handle success
    else
      # handle timeout failure
    end