how to raise a timeout error manually? - ruby

I want to test a http get request. output something if timeout.
begin
url = "#{url}?#{params.to_param}"
Net::HTTP.get_response(URI.parse(url))
rescue Timeout::Error
puts "....."
end
How to raise a timeout error manually? or how to set a shorter timeout number for http request?
For a http request, should I change the default timeout number? How long is appropriate?

Based on http://opensourceconnections.com/blog/2008/04/24/adding-timeout-to-nethttp-get_response/
http = Net::HTTP.new(url.host, url.port)
http.read_timeout = 5
http.open_timeout = 5
resp = http.start() {|http|
http.get(url.path)
}
puts resp.kind_of? Net::HTTPResponse
puts resp.code
puts resp.body

To set timeout use:
http = Net::HTTP.new(host_param)
http.read_timeout = 500
There are few types of timeouts you can set. From docs:
open_timeout:
Number of seconds to wait for the connection to open.
Any number may be used, including Floats for fractional seconds.
If the HTTP object cannot open a connection in this many seconds,
it raises a Net::OpenTimeout exception. The default value is nil.
read_timeout:
Number of seconds to wait for one block to be read (via one read(2) call).
Any number may be used, including Floats for fractional seconds.
If the HTTP object cannot read data in this many seconds,
it raises a Net::ReadTimeout exception. The default value is 60 seconds.
ssl_timeout:
Sets the SSL timeout seconds.

Related

Why do we need to run start when using net/http?

If I use:
uri = URI("...")
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = 60
# Add http.start here? Why?
for i in 1..n
uri = getFullUri()
req = Net::HTTP::Get.new(uri.path)
resp = http.request(req)
end
everything works fine.
Why do I need to add an http.start?
I see that http.started? returns false everywhere if I don't add http.start, but does this have a negative impact?
Which is the difference between those 2 cases?
Do the number of TCP connections or HTTP sessions differ?
http.start() will explicitly open the TCP connection at the point in time that it's been called. It's automatically called by http.request() if it hasn't been called already. To wit, here's the first few lines of the request method:
def request(req, body = nil, &block) # :yield: +response+
unless started?
start {
req['connection'] ||= 'close'
return request(req, body, &block)
}
end
Assuming getFullUri() takes less than a couple of seconds to run (see the keep_alive_timeout attribute), the original connection should be reused regardless of how it was created.

Ruby - timeout not working

I'm expecting this piece of code to run for no longer than 5 seconds:
require 'httpi'
require 'timeout'
puts Time.new
begin
request,response=nil,nil
Timeout::timeout(5){
request=HTTPI::Request.new(url: "http://example.com")
response=HTTPI.get(request)
}
rescue
puts "except: #{$!}"
ensure
puts Time.new
end
But this is the output I'm getting:
2016-11-04 09:44:55 -0400
D, [2016-11-04T09:44:55.916557 #2476] DEBUG -- : HTTPI GET request to example.com (net_http)
except: execution expired
2016-11-04 09:45:16 -0400
I'm assuming NET's default HTTP timeout is 20 seconds, so Timeout::timeout is just allowing the code to run however long it wants. Why?
As you can see here, here and here, the Ruby's Timeout module is famous for having some problems.
You should consider not using this module, unless it is extremely necessary.
Instead, you can use the read_timeout and/or open_timeout options provided by the HTTPI's API.
request = HTTPI::Request.new(url: "http://example.com")
request.open_timeout = 5 # seconds
request.read_timeout = 5 # seconds
response = HTTPI.get(request)

Net::OpenTimeout: execution expired on background third party API call

I have Sidekiq 5 workers, concurrency 50. My webapp make third party API calls every few minutes, averagely 15000 requests per hour. Each hour I have near 10 errors Net::OpenTimeout: execution expired. Looks like not a big problem, but I want to know how to deal with it. Thanks.
def grabber(url)
response, body = nil
uri = URI(url)
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https', :read_timeout => 1000) do |http|
request = Net::HTTP::Get.new uri
response = http.request request
end
if response.code == '200'
body = JSON.parse(response.body)
end
body
end
Net::HTTP throws an exception when request time out occurs.
You can just catch exceptions and do something with it:
rescue Net::OpenTimeout
#do something
Here you can get some examples.

Can I let the connection time out but still get the response?

I have a function that gets response over http. It runs some tests. Lately it started to happen that the test never finishes. So I introduced a time out. Then I found out that if I stop the database server the test script finishes with a db error that is in fact very good lead why the test didn't finish as expected. So to get the error could help to save me time. Because I wouldn't have to reproduce the whole test again manually.
Q1: Is there any way to let the connection time out but then get the response after the database server is restarted? Note that I cannot send the http request again as it would start the same text again.
Q2: I think that a solution would be to introduce timer while "waiting" for http response. But I don't know how to do that. Any idea?
My function is like
def execute_db2_script(url)
db2_database = 'RATIONAL'
http_read_timeout=$http_read_timeout
uri = URI.parse(url)
start = Time.new
connection = Net::HTTP.new(uri.host, 443)
connection.use_ssl = true
begin
response = connection.start() do |http|
http.open_timeout = 50
http.read_timeout = http_read_timeout
http.request_get(uri.request_uri)
end
rescue Timeout::Error
time_out_message ="security time out - after #{$http_read_timeout} sec"
return time_out_message
end
return response.body.gsub("\n","<BR>")
end
You can use retry keyword
def execute_db2_script(url)
...
begin
...
rescue Timeout::Error
time_out_message ="security time out - after #{$http_read_timeout} sec"
if "the server is going to restart then"
retry # this will restart begin-rescue-end block again
else
return time_out_message
end
end
response.body.gsub("\n","<BR>")
end

How to implement timer that runs independently along with http request?

I have a ruby code that triggers php script over https.
Use case: The php script usually finishes in 5 minutes so I have set up time out for https request after 10 minutes. I need a timer that would trigger code after let's say 7 minutes after the https request started.
I was thinking of using thread that I created just before I initiate https request. I am not sure if this the correct way to approach this. Maybe there is not need to use threads at all. I am using ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]. Also I don't now if I can 'kill' the thread on successful finish of https request.
uri = URI.parse(url)
start = Time.new
http_read_timeout=60*10
connection = Net::HTTP.new(uri.host, 443)
connection.use_ssl = true
begin
response = connection.start() do |http|
http.open_timeout = 50
http.read_timeout = http_read_timeout
http.request_get(uri.request_uri)
# here I need to place a code that is triggered
# in case of custom timeout is reached
end
rescue Timeout::Error
# "Connection failed
time_out_message ="security time out - after #{http_read_timeout} sec"
return time_out_message
end
puts "finished"
The basic structure could be like this:
seconds_timer = MyDelay
counter = 0
test_thread = Thread.new do
run_http_php_test
end
while test_thread.alive?
counter += 1
if counter > seconds_timer
handle_custom_timeout_somehow
# if you want to halt run_http_php_test:
test_thread.kill if test_thread.alive?
# otherwise:
break
end
sleep 1
end
# the below doesn't apply if you kill the run_http_php_test thread
test_thread.join if test_thread.alive?
...but of course you could change that sleep 1 to whatever polling interval you like. Polling is nicer than just forcing your original thread to sleep, because the code will finish faster if run_http_php_test is done before you hit your custom timeout value.
Most or all of your code above can be in the run_http_php_test method, or inserted directly...whichever you'd prefer.
ruby 1.9.3 implements timeout module that has a timeout function. you can see it here. if you scroll down you can click show source and see the definition for timeout method. you can copy it if you dont want to upgrade to ruby 1.9.3 (I recommend upgrade since 1.8.7 is very slow compared to 1.9.3)

Resources