34

I have a post happening to a rails application from a ruby script. The script creates a variable request as

request = Net::HTTP::Post.new(url.path) 

which is then used as follows

request.content_type = "application/json" request.body = JSON.generate( params ) response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)} 

There is quite a lot of processing happening on the server side, and I'm getting a Net::ReadTimeout error

I tried to specify a timeout period

request.read_timeout = 500 

as per this stackoverflow answer but I got a

undefined method `read_timeout=' for #<Net::HTTP::Post POST> (NoMethodError) 

error. I assume that I'm missing something simple somewhere. All clues gratefully received

Technical info:

  • Ruby 2.0.0p247
  • Rails 4.0.0
  • Windows 7 32 bit ruby
3

5 Answers 5

47

Solved via this stackoverflow answer

I've changed my

response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)} 

line to be

response = Net::HTTP.start(url.host, url.port, :read_timeout => 500) {|http| http.request(request)} 

and this seems to have got around this problem.

Sign up to request clarification or add additional context in comments.

3 Comments

If it's posting, seems like write_timeout would make sense. :)
What about a HTTP.get?
FYI: according to ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/… it seems that the read timeout is in seconds. The parameter is called sec but no further documentation is provided.
35

The read_timeout is available with a plain Net::HTTP object:

url = URI.parse('http://google.com') http = Net::HTTP.new(url.host, url.port) http.read_timeout = 5 # seconds http.request_post(url.path, JSON.generate(params)) do |response| # do something with response p response end 

Comments

1

One thing to keep in mind is that if read_timeout is set to a small value such that a timeout does occur...Net::HTTP will "helpfully" retry the request. For a slow HTTP server, a timeout error may not be raised to the code calling Net::HTTP until 2x the read_timeout value.

This certainly was not the behavior I expected.

More info on this topic and how possible solutions differ for Ruby < 2.5 and >= 2.5 may be found here:

https://stackoverflow.com/a/59186209/5299483

Comments

1

I catch both OpenTimeout and ReadTimeout and it's work. test in Ruby:2.6.5

def ping(host, port) begin url = URI.parse("http://#{host}:#{port}/ping") req = Net::HTTP::Get.new(url.to_s) # setting both OpenTimeout and ReadTimeout res = Net::HTTP.start(url.host, url.port, :open_timeout => 3, :read_timeout => 3) {|http| http.request(req) } if JSON.parse(res.body)["ok"] # return true STDERR.puts "#{host}:#{port} is reachable" else STDERR.puts "#{host}:#{port} is NOT reachable" end rescue Net::ReadTimeout => exception STDERR.puts "#{host}:#{port} is NOT reachable (ReadTimeout)" rescue Net::OpenTimeout => exception STDERR.puts "#{host}:#{port} is NOT reachable (OpenTimeout)" end end ping("#{ENV['FIRST_HOST']}", 2345) ping("#{ENV['SECOND_HOST']}", 2345) 

Comments

-9

If anyone is still facing timeout setting issue and Net::HTTP timeout not working as expected, then you may follow below approach as well:

begin Timeout::timeout(10) { #### ## YOUR REQUEST CODE WILL BE HERE #### } rescue 408 end 

2 Comments

You should be aware that Timeout uses threads and you need to be aware of the implications of that.
Ruby’s Timeout is a giant hammer and will only lead to a big mess. Don’t use it. mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.