Search code examples
ruby-on-railshttphttpsconnection-poolingtyphoeus

Typhoeus does not close https connections


I'm using Typhoeus to handle all of the HTTP calls to external APIs on my site, and it's been working beautifully up until recently. My Rails site started to be unresponsive after a while. I noticed that there're a ton of connections in the CLOSE_WAIT state when I do a netstat, and they're generated by the following piece of code.

  requests = []
  hydra = Typhoeus::Hydra.new
  urls.each_with_index do |url, index|
    request = Typhoeus::Request.new(url, :timeout => 5000)
    request.on_complete do |response|
      begin
        resp = JSON.parse(response.body)

        if resp["error"]
          p "no deal found for #{factual_ids[index]}"
          { :deals => nil }
        else
          { :deals => resp["merchant"]["deals"] }
        end
      rescue Exception => e
        p e.message
        { :deals => nil }
      end
    end

    requests << request
    hydra.queue(request)
  end

  hydra.run

The only thing that I find different than how I am using Typhoeus in my other HTTP calls is that the urls above are all HTTPS urls. I don't know if that is of any significance but that's the only thing I can think of at this moment. Has anyone seen this before? Is there a option I can pass into Typheous to force close the connection once it's finished?


Solution

  • Which operating system and Typhoeus version are you using? Some folks with ubuntu seem to run into similar issues. Typhoeus 0.5 is not yet released, but the release candidate which supports the forbid_reuse option.

    Typhoeus::Request.new(url, :timeout => 5000, :forbid_reuse => true)
    

    This is the issue: https://github.com/typhoeus/typhoeus/issues/205 and here is the libcurl documentation: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTFORBIDREUSE.

    Your code would look like that for Typhoeus 0.5:

    requests = []
    Typhoeus.on_complete do |response|
      begin
        resp = JSON.parse(response.body)
    
        if resp["error"]
          p "no deal found for #{factual_ids[index]}"
          response.options[:response_body] = { :deals => nil }
        else
          response.options[:response_body] = { :deals => resp["merchant"]["deals"] }
        end
      rescue Exception => e
        p e.message
        response.options[:response_body] = { :deals => nil }
      end
    end
    
    hydra = Typhoeus::Hydra.new
    urls.each_with_index do |url, index|
      request = Typhoeus::Request.new(url, :timeout => 5000)
      requests << request
      hydra.queue(request)
    end
    
    hydra.run