Handling Timeout error - ruby-on-rails

After using timeout:
status = Timeout::timeout(5) {
# Something that should be interrupted if it takes too much time...
}
I got this Timeout error:
/Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/net/http.rb:644:in `initialize': execution expired (Timeout::Error)
from /Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/net/http.rb:644:in `open'
from /Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/net/http.rb:644:in `block in connect'
from /Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/timeout.rb:44:in `timeout'
from /Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/timeout.rb:87:in `timeout'
from /Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/net/http.rb:644:in `connect'
from /Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/net/http.rb:637:in `do_start'
from /Users/galharth/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/net/http.rb:632:in `start'
from /Users/galharth/.rvm/gems/ruby-1.9.2-p136/gems/mechanize-1.0.0/lib/mechanize.rb:527:in `fetch_page'
from /Users/galharth/.rvm/gems/ruby-1.9.2-p136/gems/mechanize-1.0.0/lib/mechanize.rb:259:in `get'
What should I do?

Well, that's expected behaviour of Timeout. If the block takes too long, its execution gets terminated and an exception thrown.
You would probably like to catch the exception and handle it appropriately:
require 'timeout'
begin
status = Timeout::timeout(5) {
# Something that should be interrupted if it takes too much time...
}
rescue Timeout::Error
puts 'That took too long, exiting...'
end

uri = URI.parse("https://example.com")
# Full control
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
#http.read_timeout = 500
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"locationcode" => "999", "sublocationcode" => "1"})
response = http.request(request)
render :json => response.body

Related

Ruby on rails sslv3 alert handshake failure

I am trying to make HTTPS API request to Salesforce instance. I am trying to connect from localhost and windows machine.
SALESFORCE_URL = "https://my.salesforce.com"
TOKEN_URL = "services/oauth2/token"
request_params = {
"grant_type" => "password",
"client_id" => "3MVG9gOZsF7exF8Pn79zdsxuntzX_0TlVPRKL0R8iPxBQ8dHqh14yzg",
"client_secret" => "272142298328091392325",
"redirect_url" => "https://localhost:3000/RestTest/oauth/_callback",
"username" => "user#xyz.com",
"password" => "xyz#2018",
}
url = SALESFORCE_URL + "/" + TOKEN_URL
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
request.body = request_params.to_json
response = http.request(request)
Rails.logger.info response.inspect
I am getting below error.
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: sslv3 alert handshake failure
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/net/http.rb:800:in `connect'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/net/http.rb:800:in `block in connect'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/timeout.rb:55:in `timeout'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/timeout.rb:100:in `timeout'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/net/http.rb:800:in `connect'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/net/http.rb:756:in `do_start'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/net/http.rb:745:in `start'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/right_http_connection-1.3.0/lib/net_fix.rb:129:in `request'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/rest-client-1.6.7/lib/restclient/net_http_ext.rb:51:in `request'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.7.1.188/lib/new_relic/agent/instrumentation/net.rb:27:in `block (2 levels) in request_with_newrelic_trace'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.7.1.188/lib/new_relic/agent.rb:400:in `disable_all_tracing'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.7.1.188/lib/new_relic/agent/instrumentation/net.rb:26:in `block in request_with_newrelic_trace'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.7.1.188/lib/new_relic/agent/cross_app_tracing.rb:41:in `trace_http_request'
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.7.1.188/lib/new_relic/agent/instrumentation/net.rb:23:in `request_with_newrelic_trace'
C:/Users/user/Home/projects/portcullis/mainNew/lib/tasks/salesforce.rake:41:in `block (2 levels) in <top (required)>'
Why I am getting this error?
Salesforce does not support SSLv3 (POODLE Vulnerability).
Check the suported ciphers using online tools like Comodo's SSL Analyzer or Qualys SSL Labs and configure your HTTP client
connection.ssl_version = :TLSv1 or :TLSv1_2

Mechanize get page - Conn close because of error end of file reached

I have this problem with an simple request with mechanize in my production code, in local works ok, but in production environment not, can you help me? thanks.
agent = Mechanize.new
agent.log = Logger.new $stderr
agent.agent.http.debug_output = $stderr
page = agent.get "THE_URL_EXAMPLE"
I get this error:
too many connection resets (due to end of file reached - EOFError) after 0 requests on 54261840, last used 1491919097.3684318 seconds ago
I am working with ruby 2.0.0 and mechanize 2.7.5
I try change the keep_alive to false, add an idle_timeout, this code: http://scottwb.com/blog/2013/11/09/defeating-the-infamous-mechanize-too-many-connection-resets-bug/ but nothing work.
2.0.0 :119 > page = agent.get uri
Net::HTTP::Get: MY_ACTION_EXAMPLE
request-header: accept-encoding => gzip,deflate,identity
request-header: accept => /
request-header: user-agent => Mechanize/2.7.5 Ruby/2.0.0p451 (http://github.com/sparklemotion/mechanize/)
request-header: connection => close
request-header: accept-charset => ISO-8859-1,utf-8;q=0.7,*;q=0.7
request-header: accept-language => en-us,en;q=0.5
request-header: host => MY_HOST_EXAMPLE
request-header: x-requested-with => XMLHttpRequest
opening connection to MY_HOST_EXAMPLE:80...
opened
<- "GET MY_ACTION_EXAMPLE HTTP/1.1\r\nAccept-Encoding: gzip,deflate,identity\r\nAccept: /\r\nUser-Agent: Mechanize/2.7.5 Ruby/2.0.0p451 (http://github.com/sparklemotion/mechanize/)\r\nConnection: close\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nAccept-Language: en-us,en;q=0.5\r\nHost: MY_HOST_EXAMPLE\r\nX-Requested-With: XMLHttpRequest\r\n\r\n"
Conn close because of error end of file reached, and retry
opening connection to MY_HOST_EXAMPLE:80...
opened
<- "GET MY_ACTION_EXAMPLE HTTP/1.1\r\nAccept-Encoding: gzip,deflate,identity\r\nAccept: /\r\nUser-Agent: Mechanize/2.7.5 Ruby/2.0.0p451 (http://github.com/sparklemotion/mechanize/)\r\nConnection: close\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nAccept-Language: en-us,en;q=0.5\r\nHost: MY_HOST_EXAMPLE\r\nX-Requested-With: XMLHttpRequest\r\n\r\n"
Conn close because of error end of file reached
Conn close because of error end of file reached
Net::HTTP::Persistent::Error: too many connection resets (due to end of file reached - EOFError) after 0 requests on 67857800, last used 1491937635.2713494 seconds ago
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/protocol.rb:153:in `read_nonblock'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/protocol.rb:153:in `rbuf_fill'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/protocol.rb:134:in `readuntil'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/protocol.rb:144:in `readline'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/http/response.rb:39:in `read_status_line'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/http/response.rb:28:in `read_new'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/http.rb:1406:in `block in transport_request'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/http.rb:1403:in `catch'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/http.rb:1403:in `transport_request'
from /usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/net/http.rb:1376:in `request'
from /home/deploy/www/shared/bundle/ruby/2.0.0/gems/net-http-persistent-2.9.4/lib/net/http/persistent.rb:999:in `request'
from /home/deploy/www/shared/bundle/ruby/2.0.0/gems/mechanize-2.7.5/lib/mechanize/http/agent.rb:274:in `fetch'
from /home/deploy/www/shared/bundle/ruby/2.0.0/gems/mechanize-2.7.5/lib/mechanize.rb:464:in `get'
from (irb):119
from /home/deploy/www/shared/bundle/ruby/2.0.0/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
from /home/deploy/www/shared/bundle/ruby/2.0.0/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
from /home/deploy/www/shared/bundle/ruby/2.0.0/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'2.0.0 :120 >
And it is only that url that is the strangest yet..
Please help me. Thanks.

Withings API: The callback URL is either unknown or invalid

I'm trying to set a notification in the withings API (with the withings-simplificator gem). I always get this error, no matter what URL I enter or if I encode it or not:
irb(main):013:0> user.subscribe_notification('http://foo.bar.com', 'test subscription')
Withings::ApiError: The callback URL 'http://foo.bar.com' is either unknown or invalid - Status code: 293
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:80:in `verify_response!'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:22:in `get_request'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:27:in `get_request'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/user.rb:26:in `subscribe_notification'
from (irb):13
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/console.rb:110:in `start'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/console.rb:9:in `start'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:68:in `console'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:8:in `require'
from bin/rails:8:in `<main>'
Has anyone encountered this and has a solution?
Update 1:
So I tried without the withings simplificator gem:
API_KEY = '123'
API_SECRET = '456'
USER_ID = '789'
USER_KEY = 'abc'
USER_SECRET = 'def'
CONFIGURATION = { site: 'https://oauth.withings.com',
request_token_path: '/account/request_token',
access_token_path: '/account/access_token',
authorize_path: '/account/authorize',
http_method: :get,
scheme: :query_string
}
#consumer = OAuth::Consumer.new API_KEY, API_SECRET, CONFIGURATION
#access_token = OAuth::AccessToken.new #consumer, USER_KEY, USER_SECRET
url = ERB::Util.url_encode("www.foo.bar/trigger")
comment = ERB::Util.url_encode("Trigger")
response = #access_token.get("https://wbsapi.withings.net/notify?action=subscribe&userid=#{USER_ID}&callbackurl=#{url}&comment=#{comment}")
JSON.parse(response.body)
And same error:
irb(main):051:0> JSON.parse(response.body)
=> {"status"=>293}
What am I doing wrong?
You have to make sure during setup
your "trigger url" exists
it responds with "ok" to a POST
it is fast ... I couldn't figure this out exactly how fast, but I think the response time should be < 1 second
With an environment like this, my code above works.
Your notification endpoint going to do two operations:
it is going to respond test request response (while you register it will check your URL is exist or not). You will receive call with empty body object. If it is not have userid, it is not a data notification, so you have to respond status as 200 with empty body;
after successful registration you will receive data alert. This time you can handle by your business logic.

RestClient::RequestTimeout in controller#method ruby on rails

I am making the following rest get request:
rest_user = JSON.parse(RestClient.get APP_CONFIG['api_url'] + "users/", :params => {:token => APP_CONFIG['token'], :full => 'true'} )["users"]
I get the following error back after a minute:
RestClient::RequestTimeout in controller#method
rbenv/versions/1.8.7-p374/lib/ruby/gems/1.8/gems/rest-client-1.6.7/lib/restclient/request.rb:184:in `transmit'
rbenv/versions/1.8.7-p374/lib/ruby/gems/1.8/gems/rest-client-1.6.7/lib/restclient/request.rb:64:in `execute'
rbenv/versions/1.8.7-p374/lib/ruby/gems/1.8/gems/rest-client-1.6.7/lib/restclient/request.rb:33:in `execute'
rbenv/versions/1.8.7-p374/lib/ruby/gems/1.8/gems/rest-client-1.6.7/lib/restclient.rb:68:in `get'
Now when I am tailing the logs of the actual service that is receiving this request, it is performing the requested request and completes it without any error.
But the consumer(the web applicaion) is throwing the request timeout error before the request has actually been fully completed.
It is absolutely normal. Your web app raises an error, because RestClient raises an error after 60 seconds if it has not received response yet.
The app you are calling has no knowledge of that fact, so it continues processing as long as it is required to complete the request (it may take, 61 seconds, 70, ... ).
url = APP_CONFIG['api_url'] + "users/"
payload = {:token => APP_CONFIG['token'], :full => 'true'}
RestClient::Execute.execute(method: :get, url: url, payload: payload, timeout: 120)

How to specify a read timeout for a Net::HTTP::Post.new request in Ruby 2

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
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.
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
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
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)
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

Resources