I have a script that spiders a website, its based on Mechanize and seems to be working great except for what seems like an error I can't catch. 'Errno::ECONNRESET' This seems to reset the connection and print the error, but it doesn't seem to raise an exception. What is the best way to deal with this? I will put the program flow in pseudo code below.
while LinksQue.notEmpty
begin
mech.get(LinksQue.nextLink)
rescue Mechanize::ResponseCodeError => e
puts e.response_code
puts "this is a bad link"
rescue Errno::ECONNRESET
#This doesn't work
end
end
Part of my problem is that my method for marking a link as 'visited' or as a 'bad link' is a DB so unless I can update the DB in a rescue block it will just keep trying the same link again and again.
Related
Recently, I am working on mobile automation using appium+selenium in ruby. But stopped by the following issue: selenium driver is quit automatically (mobile app is closed) every time an exception happens. This will result in that the following code to access the driver will fail after I manage to rescue the exception.
e.g.
begin
#driver.find_element(:xpath, "//window[1]/button[27]")
rescue
#driver.find_element(:xpath, "//window[1]/navigationBar[1]/button[2]").click
end
Does anyone have this issue as well?
According to http://www.ruby-doc.org/core-2.1.1/doc/syntax/exceptions_rdoc.html "By default StandardError and its subclasses are rescued. You can rescue a specific set of exception classes (and their subclasses) by listing them after rescue:
begin
# ...
rescue ArgumentError, NameError
# handle ArgumentError or NameError
end
I assume you are waiting for something like ElementNotVisibleException. So, add type of exception after rescue. Something like rescue ElementNotVisibleException.
I use rufus scheduler to run overnight test scripts by calling my functions.
Sometimes I can see "scheduler caught exception:" a message that threw some of my functions. Then scheduler stops execution of following test cases.
How can I make it so scheduler runs all test cases regardless of any exception caught?
This is called "exception swallowing". You intercept an exception and don't do anything with it.
begin
# do some dangerous stuff, like running test scripts
rescue => ex
# do nothing here, except for logging, maybe
end
If you do not need to do anything with the exception, you can omit the => ex:
begin
# do some dangerous stuff, like running test scripts
rescue; end
If you need to rescue Exceptions that don't subclass from StandardError, you need to be more explicit:
begin
# do some dangerous stuff, like running test scripts
rescue Exception
# catches EVERY exception
end
I will sometimes use the fact that you can pass blocks to a method, and I have the method rescue errors, and my code can continue on its way.
def check_block
yield
rescue NoMethodError => e
<<-EOR
Error raised with message "#{e}".
Backtrace would be #{e.backtrace.join('')}
EOR
end
puts check_block {"some string".sort.inspect}
puts check_block {['some', 'array'].sort.inspect}
This first block will go through and rescue with a report returned, the second will operate normally.
This rescue only rescues NoMethodError while you may need to rescue other errors.
What’s the best way to rescue exceptions from Net::HTTP?
Exceptions thrown are described in Ruby’s socket.c, like Errno::ETIMEDOUT, Errno::ECONNRESET, and Errno::ECONNREFUSED. The base class to all of these is SystemCallError, but it feels weird to write code like the following because SystemCallError seems so far removed from making an HTTP call:
begin
response = Net::HTTP.get_response(uri)
response.code == "200"
rescue SystemCallError
false
end
Is it just me? Is there a better way to handle this beyond fixing Net::HTTP to handle the Errno exceptions that would likely pop up and encapsulate them in a parent HttpRequestException?
I agree it is an absolute pain to handle all the potential exceptions. Look at this to see an example:
Working with Net::HTTP can be a pain. It's got about 40 different ways
to do any one task, and about 50 exceptions it can throw.
Just for the love of google, here's what I've got for the "right way"
of catching any exception that Net::HTTP can throw at you:
begin
response = Net::HTTP.post_form(...) # or any Net::HTTP call
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
...
end
Why not just rescue Exception => e? That's a bad habit to get into, as
it hides any problems in your actual code (like SyntaxErrors, whiny
nils, etc). Of course, this would all be much easier if the possible
errors had a common ancestor.
The issues I've been seeing in dealing with Net::HTTP have made me
wonder if it wouldn't be worth it to write a new HTTP client library.
One that was easier to mock out in tests, and didn't have all these
ugly little facets.
What I've done, and seen most people do, is move away from Net::HTTP and move to 3rd party HTTP libraries such as:
httparty and faraday
I experienced the same problem, and after a lot of research, I realized the best way to to handle all exceptions Net::HTTP methods would throw is to rescue from StandardError.
As pointed by Mike Lewis's answer, Tammer Saleh blog post proposes rescuing from a lot exceptions, but it is still flaw. There are some exceptions he does not rescue from, like Errno::EHOSTUNREACH, Errno::ECONNREFUSED, and possible some socket exceptions.
So, as I found out in tenderlove's translation of an old ruby-dev thread, the best solution is rescuing from StandardError, unfortunately:
begin
response = Net::HTTP.get_response(uri)
rescue StandardError
false
end
It is awful, but if you want your system does not break because of these other exceptions, use this approach.
Another approach is to aggregate all these exceptions in a constant, and then re-use this constant, e.g.:
ALL_NET_HTTP_ERRORS = [
Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
]
begin
your_http_logic()
rescue *ALL_NET_HTTP_ERRORS
…
end
It is far more maintainable and cleaner.
However, word of warning. I've copied the possible exceptions list from the aforementioned Tammer Saleh's blog post, and I know that his list is incomplete. For instance, Net::HTTP.get(URI("wow")) raises Errno::ECONNREFUSED which is not listed. Also, I wouldn't be surprised if the list should be modified for different Ruby versions.
For this reason, I recommend sticking to rescue StandardError in most cases. In order to avoid catching too much, move as much as possible outside the begin-rescue-end block, preferably leave only a call to one of the Net::HTTP methods.
Your intuition on this is right, for the most robust solution, I'd probably rescue each one individually (or in small groups) and take the appropriate action, like trying the connection again, or abandoning the request all together. I like to avoid using a very high-level/generic rescue because it might catch exceptions that I'm not prepared for or didn't expect.
I have a set of cucumber tests that get run on a build server.
I often want faster feedback than the server directly provides and so I watch the console output as it runs. I was wanting a way of identifying any failing test with a single search term so I modified our Around to print "Failed Test" on any exception, but Ruby doesn't seem to be handing the exception back up to the around. I've verified this by having puts statements after the begin ... end.
Does anyone know why this is happening or a way of wrapping any exception thrown from a failing test in a begin?
Around() do |scenario, block|
begin
Timeout.timeout(0.1) do
block.call
end
rescue Timeout::Error => e
puts "Failed Test"
puts caller
rescue Exception => e
puts "Failed Test"
raise e
end
end
Looking at cucumber 1.3.12 it actually rescues any exceptions from scenario steps. So you can't see them in any way without modifying cucumber gem.
See my answer on how to put a debug hook in that place for more information:
https://stackoverflow.com/a/22654786/520567
Have you tried disabling Cucumber's exception capturing with the #allow-rescue tag?
#allow-rescue: Turns off Cucumber’s exception capturing for the tagged scenario(s). Used when the code being tested is expected to raise and handle exceptions.
https://github.com/cucumber/cucumber/wiki/Tags
i have a products controller on my site and what i decided to do is use the rescue command in rails so that people can't enter products/500 and get the rails error message for a product that doesn't exist. here's what my code looks like
def show
#product = Product.find(params[:id])
#title = #product.name
rescue ActiveRecord::RecordNotFound
redirect_to root_path, :notice => 'No such product'
end
but then i saw some other places where people use begin rescue and else. is the code below a better practice. it works both ways, but i would like to know what the difference is between these two codes
def show
begin
#product = Product.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to root_path, :notice => 'No such product'
else
#title = #product.name
end
end
One isolates the thing that causes the exception, one doesn't.
Not really sure if one is a "better practice" or not; I like to keep "things that can go horribly wrong" isolated, but I find begin/rescue/else unwieldy when reading, because I have to "skip ahead" to see what happens if there isn't an exception. Not a lot, but meh.
The reason you'd want to use the begin/rescue/else (and optional ensure) is if you're going to do something else afterwards. In your case, the first of your examples is preferable. It groups the "happy case" logic together, which is most of what you will likely want to focus on, but still leaves it clear what will happen if there is a failure.