Can anyone explain why I might see this stack (caused by an HTTParty::post request) when the call to the method looks like this:
begin
response = HTTParty::post(url, options)
rescue
logger.warn("Could not post to #{url}")
rescue Timeout::Error
logger.warn("Could not post to #{url}: timeout")
end
The stack:
/usr/local/lib/ruby/1.8/timeout.rb:64:in `timeout'
/usr/local/lib/ruby/1.8/net/protocol.rb:134:in `rbuf_fill'
/usr/local/lib/ruby/1.8/net/protocol.rb:104:in `read_all'
/usr/local/lib/ruby/1.8/net/http.rb:2228:in `read_body_0'
/usr/local/lib/ruby/1.8/net/http.rb:2181:in `read_body'
/usr/local/lib/ruby/1.8/net/http.rb:2206:in `body'
/usr/local/lib/ruby/1.8/net/http.rb:2145:in `reading_body'
/usr/local/lib/ruby/1.8/net/http.rb:1053:in `request_without_newrelic_trace'
[GEM_ROOT]/gems/newrelic_rpm-3.1.1/lib/new_relic/agent/instrumentation/net.rb:20:in `request'
[GEM_ROOT]/gems/newrelic_rpm-3.1.1/lib/new_relic/agent/method_tracer.rb:242:in `trace_execution_scoped'
[GEM_ROOT]/gems/newrelic_rpm-3.1.1/lib/new_relic/agent/instrumentation/net.rb:19:in `request'
/usr/local/lib/ruby/1.8/net/http.rb:1037:in `request_without_newrelic_trace'
/usr/local/lib/ruby/1.8/net/http.rb:543:in `start'
/usr/local/lib/ruby/1.8/net/http.rb:1035:in `request_without_newrelic_trace'
[GEM_ROOT]/gems/newrelic_rpm-3.1.1/lib/new_relic/agent/instrumentation/net.rb:20:in `request'
[GEM_ROOT]/gems/newrelic_rpm-3.1.1/lib/new_relic/agent/method_tracer.rb:242:in `trace_execution_scoped'
[GEM_ROOT]/gems/newrelic_rpm-3.1.1/lib/new_relic/agent/instrumentation/net.rb:19:in `request'
[GEM_ROOT]/gems/httparty-0.7.8/lib/httparty/request.rb:69:in `perform'
[GEM_ROOT]/gems/httparty-0.7.8/lib/httparty.rb:390:in `perform_request'
[GEM_ROOT]/gems/httparty-0.7.8/lib/httparty.rb:358:in `post'
[GEM_ROOT]/gems/httparty-0.7.8/lib/httparty.rb:426:in `post'
As you can see, I am handling the Timeout::Error exception. This is in Ruby 1.8.7. I am well aware that in Ruby 1.8.7, StandardException and TimeoutException have different inheritance trees, so I handle both, but it does not seem to make a difference.
When you omit the exception class in rescue, it will capture any StandardError. Since Timeout::Error is a subclass of StandardError, it will be captured by the first rescue statement. If you want to separately capture it, you have to place that before the omitted one:
begin
response = HTTParty::post(url, options)
rescue Timeout::Error
logger.warn("Could not post to #{url}: timeout")
rescue
logger.warn("Could not post to #{url}")
end
Related
I am trying to automate some interaction with a web app, but capybara keeps throwing this
{"id":"c0616941-0375-4c42-a6d8-a3a5201c5235","name":"tag_name","args":[3,1]}
{"command_id":"c0616941-0375-4c42-a6d8-a3a5201c5235","error":{"name":"Poltergeist.ObsoleteNode","args":[]}}
Capybara::Poltergeist::ObsoleteNode: Capybara::Poltergeist::ObsoleteNode
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/poltergeist-1.14.0/lib/capybara/poltergeist/node.rb:21:in `rescue in command'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/poltergeist-1.14.0/lib/capybara/poltergeist/node.rb:17:in `command'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/poltergeist-1.14.0/lib/capybara/poltergeist/node.rb:111:in `tag_name'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/capybara-2.13.0/lib/capybara/node/element.rb:258:in `block in tag_name'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/capybara-2.13.0/lib/capybara/node/base.rb:85:in `synchronize'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/capybara-2.13.0/lib/capybara/node/element.rb:258:in `tag_name'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/capybara-2.13.0/lib/capybara/node/element.rb:374:in `inspect'
from C:/Ruby23-x64/bin/irb.cmd:19:in `<main>'
I'd like to catch this exception and throw it away, but when I try
begin
#session.first(:button, 'Save').click
rescue Capybara::Poltergeist::ObsoleteNode
puts "Whoops!"
end
It still throws the exception and doesn't print out "Whoops!".
I'd like to do some HTTP REST requests in Ruby, using rest-client gem,
Following readme.md at https://github.com/rest-client/rest-client
I wrote this simple command line script, trying to catch exceptions in case of response codes differents from 2xx:
RestClient.get('http://thisurldoesnotexist/resource') { |response, request, result, &block|
case response.code
when 200
p "It worked !"
response
else
response.return!(request, result, &block)
end
}
Hi got this on stdout output:
/home/*****/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:878:in `initialize': getaddrinfo: Name or service not known (SocketError)
from /home/solyaris/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:878:in `open'
from /home/solyaris/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:878:in `block in connect'
from /home/solyaris/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/timeout.rb:52:in `timeout'
from /home/solyaris/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:877:in `connect'
from /home/solyaris/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:862:in `do_start'
from /home/solyaris/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:851:in `start'
from /home/solyaris/.rvm/gems/ruby-2.0.0-p247/gems/rest-client-1.6.7/lib/restclient/request.rb:172:in `transmit'
from /home/solyaris/.rvm/gems/ruby-2.0.0-p247/gems/rest-client-1.6.7/lib/restclient/request.rb:64:in `execute'
from /home/solyaris/.rvm/gems/ruby-2.0.0-p247/gems/rest-client-1.6.7/lib/restclient/request.rb:33:in `execute'
from /home/solyaris/.rvm/gems/ruby-2.0.0-p247/gems/rest-client-1.6.7/lib/restclient.rb:68:in `get'
from prova_rest.rb:3:in `<main>'
How can i catch SocketError ?
where I'm wrong ?
thanks
giorgio
The callback block is executed only when receiving some response from the server. In this case, the name resolving is failed so RestClient.get just throws an exception without entering the block. Thus just wrap your code within a begin...end construct.
begin
RestClient.get('http://thisurldoesnotexist/resource') { |response, request, result, &block|
case response.code
when 200
p "It worked !"
response
else
response.return!(request, result, &block)
end
}
rescue SocketError => e
# Handle your error here
end
class TwitterProfile < ActiveRecord::Base
def send_status_update(status_update)
if publish?
client = Twitter::Client.new( :oauth_token => authentication.token,
:oauth_token_secret => authentication.secret)
client.update(status_update.to_twitter_string)
end
rescue Exception => e
logger.info "Error publishing to twitter: #{e.to_s}"
end
end
There is a StatusUpdate model and an observer that reposts them to Twitter in after_create. I sometimes get the following exception:
NameError (undefined local variable or method `e' for #<TwitterProfile:0x00000004e44ab8>):
app/models/twitter_profile.rb:23:in `rescue in send_status_update'
app/models/twitter_profile.rb:18:in `send_status_update'
app/models/status_update_observer.rb:6:in `block in after_create'
app/models/status_update_observer.rb:4:in `after_create'
app/models/workout_observer.rb:5:in `after_update'
app/controllers/frames_controller.rb:76:in `update'
app/controllers/application_controller.rb:24:in `call'
app/controllers/application_controller.rb:24:in `block (2 levels) in <class:ApplicationController>'
app/controllers/application_controller.rb:10:in `block in <class:ApplicationController>'
What am I missing here?
I have one thing I know and one that's just a wild guess.
The thing I know is that you don't need to call to_s on an overall #{} expression; that will happen automatically. But it does no harm.
My wild guess is that your test case is not really running the code you have posted. What happens if you change e to f?
I should note that rescuing Exception itself is usually a bad idea. You should rescue RuntimeError or StandardError at the highest, and preferably something more specific. You can get fairly strange errors when rescuing Exception because you interfere with threads and interpreter-level events.
You're missing the 'begin' block of the begin/rescue clause.
I'm a ruby beginner so bear with me.
I am using the selenium-webdriver and rb-appscript gems to do some webscraping. The navigation to websites seems to be driven by the Net::Http object, which has a rbuf_fill method.
Running the following code:
sites = File.open("sites.txt", "r") if File::exists?( "sites.txt" )
if sites != nil
while (line = sites.gets)
driver.switch_to.default_content
begin
driver.navigate.to line
rescue Exception
line = line.split.join("\n")
puts line + " caused a timeout."
end
end
...
Produces this error:
/opt/local/lib/ruby1.9/1.9.1/net/protocol.rb:140:in `rescue in rbuf_fill': Timeout::Error (Timeout::Error)
from /opt/local/lib/ruby1.9/1.9.1/net/protocol.rb:134:in `rbuf_fill'
from /opt/local/lib/ruby1.9/1.9.1/net/protocol.rb:116:in `readuntil'
from /opt/local/lib/ruby1.9/1.9.1/net/protocol.rb:126:in `readline'
from /opt/local/lib/ruby1.9/1.9.1/net/http.rb:2219:in `read_status_line'
from /opt/local/lib/ruby1.9/1.9.1/net/http.rb:2208:in `read_new'
from /opt/local/lib/ruby1.9/1.9.1/net/http.rb:1191:in `transport_request'
from /opt/local/lib/ruby1.9/1.9.1/net/http.rb:1177:in `request'
from /opt/local/lib/ruby1.9/1.9.1/net/http.rb:1170:in `block in request'
from /opt/local/lib/ruby1.9/1.9.1/net/http.rb:627:in `start'
from /opt/local/lib/ruby1.9/1.9.1/net/http.rb:1168:in `request'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/selenium-webdriver-2.2.0/lib/selenium/webdriver/remote/http/default.rb:73:in `response_for'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/selenium-webdriver-2.2.0/lib/selenium/webdriver/remote/http/default.rb:41:in `request'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/selenium-webdriver-2.2.0/lib/selenium/webdriver/remote/http/common.rb:34:in `call'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/selenium-webdriver-2.2.0/lib/selenium/webdriver/remote/bridge.rb:406:in `raw_execute'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/selenium-webdriver-2.2.0/lib/selenium/webdriver/remote/bridge.rb:384:in `execute'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/selenium-webdriver-2.2.0/lib/selenium/webdriver/remote/bridge.rb:171:in `switchToDefaultContent'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/selenium-webdriver-2.2.0/lib/selenium/webdriver/common/target_locator.rb:68:in `default_content'
from auto.rb:25:in `<main>'
I have no idea why I can't catch this exception. Using rescue Exception should catch everything, but as you can see my script still crashes.
I have also found sources that say you must catch the timeout explicitly so I also tried:
rescue Timeout::Error
without any luck.
Any help is greatly appreciated on this one.
Ruby version: ruby 1.9.2p290 (2011-07-09 revision 32553)
OS: MacOS Snow Leopard 10.6.8 64-bit
Selenium Webdriver version: 2.2.0
The file 'timeout.rb' in Ruby's standard library defines:
module Timeout
# Raised by Timeout#timeout when the block times out.
class Error < RuntimeError
So what you need to rescue is not Timeout::Exception but rather Timeout::Error or more generically RuntimeError. Then it should work.
I need to rescue a Timeout::Error raised from a the Redis library but i'm running into a problem, rescuing that specific class doesn't seem to work.
begin
Redis.new( { :host => "127.0.0.X" } )
rescue Timeout::Error => ex
end
=> Timeout::Error: Timeout::Error from /Users/me/.rvm/gems/ree-1.8.7-2011.03#gowalla/gems/redis-2.2.0/lib/redis/connection/hiredis.rb:23:in `connect'
When i try to rescue Exception it still doesn't work
begin
Redis.new( { :host => "127.0.0.X" } )
rescue Exception => ex
end
=> Timeout::Error: Timeout::Error from /Users/me/.rvm/gems/ree-1.8.7-2011.03#gowalla/gems/redis-2.2.0/lib/redis/connection/hiredis.rb:23:in `connect'
If i try to raise the exception manually, i can rescue it but don't know why i can't rescue it when it's called from within the Redis Gem (2.2.0).
begin
raise Timeout::Error
rescue Timeout::Error => ex
puts ex
end
Timeout::Error
=> nil
Any clue how to rescue this exception?
You ran this code in irb, right? The exception you are getting is not actually being raised by Redis.new. It is being raised by the inspect method, which irb calls to show you the value of the expression you just typed.
Just look at the stack trace (I shortened the paths to make it legible):
ruby-1.8.7-p330 :009 > Redis.new(:host => "google.com")
Timeout::Error: time's up!
from /.../SystemTimer-1.2.3/lib/system_timer/concurrent_timer_pool.rb:63:in `trigger_next_expired_timer_at'
from /.../SystemTimer-1.2.3/lib/system_timer/concurrent_timer_pool.rb:68:in `trigger_next_expired_timer'
from /.../SystemTimer-1.2.3/lib/system_timer.rb:85:in `install_ruby_sigalrm_handler'
from /..../lib/ruby/1.8/monitor.rb:242:in `synchronize'
from /.../SystemTimer-1.2.3/lib/system_timer.rb:83:in `install_ruby_sigalrm_handler'
from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `call'
from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `initialize'
from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `new'
from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `connect'
from /.../SystemTimer-1.2.3/lib/system_timer.rb:60:in `timeout_after'
from /.../redis-2.2.2/lib/redis/connection/ruby.rb:115:in `with_timeout'
from /.../redis-2.2.2/lib/redis/connection/ruby.rb:25:in `connect'
from /.../redis-2.2.2/lib/redis/client.rb:227:in `establish_connection'
from /.../redis-2.2.2/lib/redis/client.rb:23:in `connect'
from /.../redis-2.2.2/lib/redis/client.rb:247:in `ensure_connected'
from /.../redis-2.2.2/lib/redis/client.rb:137:in `process'
... 2 levels...
from /.../redis-2.2.2/lib/redis/client.rb:46:in `call'
from /.../redis-2.2.2/lib/redis.rb:90:in `info'
from /..../lib/ruby/1.8/monitor.rb:242:in `synchronize'
from /.../redis-2.2.2/lib/redis.rb:89:in `info'
from /.../redis-2.2.2/lib/redis.rb:1075:in `inspect'
from /..../lib/ruby/1.8/monitor.rb:242:in `synchronize'
from /.../redis-2.2.2/lib/redis.rb:1074:in `inspect'
from /..../lib/ruby/1.8/irb.rb:310:in `output_value'
from /..../lib/ruby/1.8/irb.rb:159:in `eval_input'
from /..../lib/ruby/1.8/irb.rb:271:in `signal_status'
from /..../lib/ruby/1.8/irb.rb:155:in `eval_input'
from /..../lib/ruby/1.8/irb.rb:154:in `eval_input'
from /..../lib/ruby/1.8/irb.rb:71:in `start'
from /..../lib/ruby/1.8/irb.rb:70:in `catch'
from /..../lib/ruby/1.8/irb.rb:70:in `start'
from /..../bin/irb:17
As you can see above, the exception occurs inside inspect, not Redis.new. When you call inspect on a Redis object, instead of just printing out its state it actually does a lot of things. In this case, inspect attempts to connect to the server and throws an exception when that times out. This seems like a very bad design to me and maybe we should file a bug report to the maintainers of the Redis gem.
This leads to some interesting behavior in IRB:
Typing Redis.new(:host => "google.com") results in an exception as shown above
Typing Redis.new(:host => "google.com"); 'hello' results in '=> "hello"'
If you want to catch this exception, try calling ensure_connected inside your begin/rescue/end block.