Ruby rescue syntax error - ruby

I have the following line of code that is giving me an error:
rescue Timeout::Error => e
logs.puts("Rescued a timeout error...#{e}")
email_ids_all.each do |email_delete|
call= "/api/v2/emails/#{email_delete}/"
uri= HTTParty.delete("https://www.surveys.com#{call}",
:basic_auth => auth,
:headers => { 'ContentType' => 'application/x-www-form-urlencoded', 'Content-Length' => "0" }
)
puts "Deleted email #{email_delete}".green
log.puts("Deleted email #{email_delete}")
end
abort #abort entire script after deleting emails
end
The error I am receiving is this:
syntax error, unexpected keyword_rescue, expecting $end
rescue Timeout::Error => e
^
Essentially I am just trying to run an API delete call if the script times out. It doesn't seem to matter what I put in the block for rescue though, I receive the same error. What's wrong with my syntax on the rescue method?

The format for using rescue is as follows:
begin
# Code you want to run that might raise exceptions
rescue YourExceptionClass => e
# Code that runs in the case of YourExceptionClass
rescue ADifferentError => e
# Code that runs in the case of ADifferentError
else
# Code that runs if there was no error
ensure
# Code that always runs at the end regardless of whether or not there was an error
end
Here is a question with lots more information: Begin, Rescue and Ensure in Ruby?.

Related

How do I check the url for socket error ruby

uri = URI("http://#{url}")
res = Net::HTTP.get_response(uri) ### Code here
I read the path URLs from the txt file.
When a url socket error or timeout error is given the program closes.
To prevent it, I want to check that it does not give a url socket error.
uri = URI("http://#{url}")
if (uri== worked ) ### What should I use here?
res = Net::HTTP.get_response(uri)
end
Instead of an if statement, you should use an exception handler for this. Assuming the errors you're expecting are SocketError and Errno::ETIMEDOUT, that would look something like this:
begin
# code that might raise the error
rescue SocketError => e
# run this code in the event of a socket error
rescue Errno::ETIMEDOUT => e
# run this code in the event of a timeout
ensure
# run this code unless an error is raised that isn't accounted for
end

In RoR, how do I catch an exception if I get no response from a server?

I’m using Rails 4.2.3 and Nokogiri to get data from a web site. I want to perform an action when I don’t get any response from the server, so I have:
begin
content = open(url).read
if content.lstrip[0] == '<'
doc = Nokogiri::HTML(content)
else
begin
json = JSON.parse(content)
rescue JSON::ParserError => e
content
end
end
rescue Net::OpenTimeout => e
attempts = attempts + 1
if attempts <= max_attempts
sleep(3)
retry
end
end
Note that this is different than getting a 500 from the server. I only want to retry when I get no response at all, either because I get no TCP connection or because the server fails to respond (or some other reason that causes me not to get any response). Is there a more generic way to take account of this situation other than how I have it? I feel like there are a lot of other exception types I’m not thinking of.
This is generic sample how you can define timeout durations for HTTP connection, and perform several retries in case of any error while fetching content (edited)
require 'open-uri'
require 'nokogiri'
url = "http://localhost:3000/r503"
openuri_params = {
# set timeout durations for HTTP connection
# default values for open_timeout and read_timeout is 60 seconds
:open_timeout => 1,
:read_timeout => 1,
}
attempt_count = 0
max_attempts = 3
begin
attempt_count += 1
puts "attempt ##{attempt_count}"
content = open(url, openuri_params).read
rescue OpenURI::HTTPError => e
# it's 404, etc. (do nothing)
rescue SocketError, Net::ReadTimeout => e
# server can't be reached or doesn't send any respones
puts "error: #{e}"
sleep 3
retry if attempt_count < max_attempts
else
# connection was successful,
# content is fetched,
# so here we can parse content with Nokogiri,
# or call a helper method, etc.
doc = Nokogiri::HTML(content)
p doc
end
When it comes to rescuing exceptions, you should aim to have a clear understanding of:
Which lines in your system can raise exceptions
What is going on under the hood when those lines of code run
What specific exceptions could be raised by the underlying code
In your code, the line that's fetching the content is also the one that could see network errors:
content = open(url).read
If you go to the documentation for the OpenURI module you'll see that it uses Net::HTTP & friends to get the content of arbitrary URIs.
Figuring out what Net::HTTP can raise is actually very complicated but, thankfully, others have already done this work for you. Thoughtbot's suspenders project has lists of common network errors that you can use. Notice that some of those errors have to do with different network conditions than what you had in mind, like the connection being reset. I think it's worth rescuing those as well, but feel free to trim the list down to your specific needs.
So here's what your code should look like (skipping the Nokogiri and JSON parts to simplify things a bit):
require 'net/http'
require 'open-uri'
HTTP_ERRORS = [
EOFError,
Errno::ECONNRESET,
Errno::EINVAL,
Net::HTTPBadResponse,
Net::HTTPHeaderSyntaxError,
Net::ProtocolError,
Timeout::Error,
]
MAX_RETRIES = 3
attempts = 0
begin
content = open(url).read
rescue *HTTP_ERRORS => e
if attempts < MAX_RETRIES
attempts += 1
sleep(2)
retry
else
raise e
end
end
I would think about using a Timeout that raises an exception after a short period:
MAX_RESPONSE_TIME = 2 # seconds
begin
content = nil # needs to be defined before the following block
Timeout.timeout(MAX_RESPONSE_TIME) do
content = open(url).read
end
# parsing `content`
rescue Timeout::Error => e
attempts += 1
if attempts <= max_attempts
sleep(3)
retry
end
end

Ruby/Webdriver : Error handling log output

Here's what I'm currently doing:
def wait_for(timeout = 5)
Selenium::WebDriver::Wait.new(:timeout => timeout).until { yield }
rescue Selenium::WebDriver::Error::TimeOutError => e
puts 'Timeout Error'
rescue Selenium::WebDriver::Error::NoSuchElementError => ex
puts 'No Such Element Error'
end
Two questions:
1) Why is it showing me the Timeout Error twice? It should just time out and end the test
2) How do I get it to not show me all that extra information at the bottom? Ideally what I'd like is just for it to say "Timeout" or "No such element" and that's it.**
My log spits out alllll of this:
Loaded suite C:/2oh/qt Started
First Run Timeout Error Timeout Error E
======================================================================================================================================================================================================== Error: test_18a(Tests):
Selenium::WebDriver::Error::NoSuchElementError: no such element
(Session info: chrome=43.0.2357.134)
(Driver info: chromedriver=2.15.322448 (52179c1b310fec1797c81ea9a20326839860b7d3),platform=Windows NT 6.1 SP1
x86_64)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/response.rb:71:in
assert_ok'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/response.rb:34:in
initialize'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/http/common.rb:78:in
new'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/http/common.rb:78:in
create_response'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/http/default.rb:90:in
request'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/http/common.rb:59:in
call'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/bridge.rb:657:in
raw_execute'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/bridge.rb:635:in
execute'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/remote/bridge.rb:603:in
find_element_by'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/common/search_context.rb:61:in
find_element' C:/2oh/qttests.rb:28:in test_hdesrbf'
C:/2oh/qt.rb:13:intest_18a'
10:
11: def test_18a
12: puts "First Run" => 13: test_hdesrbf
14: end
15:
16:
The output you are seeing is telling you more information about the error you are rescuing. Don't think there is any escaping it, although it is handy because it will tell you what line of code has failed, and why. I'm not actually 100% sure why you would want to simplify the error!
The reason you are seeing the errors twice is because you are not telling the program to end. You are saying 'Hey, rescue this error type and output this text.' you're not telling it to stop. It will continue and I guess timeout finding the next element? To rectify this, instead of using puts to output your error text, use raise. This will halt the program once the text has been output. E.g
def wait_for(timeout = 5)
Selenium::WebDriver::Wait.new(:timeout => timeout).until { yield }
rescue Selenium::WebDriver::Error::TimeOutError
raise 'Timeout Error'
rescue Selenium::WebDriver::Error::NoSuchElementError
raise 'No Such Element Error'
end

How to get curb error stacktrace

How can I display the entire stacktrace where there is an error when using Curb's curl::easy? I've tried looking at http://www.rubydoc.info/github/taf2/curb/Curl/Err to get information, but don't see anything.
begin
curl.perform
rescue Curl::Err::CurlError => e
puts e.backtrace.inspect # or log it
end
UPDATE
I tried that however that didn't seem to give me a detailed error
message. Right now I'm getting a generic error message and it's hard
to debug
As Tin Man already mentioned "rubydoc.info/github/taf2/curb/Curl/Err is the list of possible errors that could be returned if Curb has a problem.".
To catch specific errors you need to rescue them individually. As you can see in my example above I am trying to rescue specifically Curl::Err::CurlError. Similarly you can add more errors as follows:
rescue Curl::Err::CurlError => e
puts "CURLERROR: === " + e.backtrace.inspect
rescue Curl::Err::AccessDeniedError => e
puts "ACCESSDENIED: === " + e.backtrace.inspect
rescue Curl::Err::TimeoutError => e
puts "TIMEOUT: === " + e.backtrace.inspect
...
end

Exit code from with Ruby + rest client

I learning ruby and playing it with restsclient I have following test the code and I'm expecting that to return 1/false. I can't seem to make it work.
n#lap-jta102:~/tsamcode$ ./get.rb
n#lap-jta102:~/tsamcode$ echo $?
0
#!/usr/bin/env ruby
require 'rest_client'
require 'json'
begin
response = RestClient.get("https://admin:admin#172.16.210.10/isam/host_records/187.0.0.1/hostnames", :content_type => :json, :accept => :json)
return true if response.code == 200
rescue => e
return false unless response != 200
end
$? is not set by return, but by exit. In fact, your return doesn't even do what you think. Try just this:
# one-returner.rb
return 1
$ ruby one-returner.rb
one-returner.rb:1:in `<main>': unexpected return (LocalJumpError)
The reason you're not getting an error in your program is the fact that you blanket-rescue this error when raised by return true (since you have an unrestricted rescue, which is a bad practice for exactly this reason, it can catch a wrong thing and leave you puzzled), and return false never executes (and thus never raises an error) due to unless.

Resources