Twitter Gem - rescue's to consider? - ruby

I'm working with the Twitter Gem and I've created a long running ruby task. I would like it to be able to handle common errors so I'm looking to build a list of those I should consider to protect against (for example the fail whale 500)
Here is the begin/end loop my code functions in:
Begin
# My (omitted) very long ruby task
# filled with Twitter API requests
rescue Errno::ENOENT
sleep(5)
logger.info "ENOENT error - attempting to retry"
retry
rescue Errno::ETIMEDOUT
sleep(5)
logger.info " Operation timed out - attempting to retry"
retry
rescue Errno::ECONNRESET
sleep(5)
logger.info "Connection reset by peer - attempting to retry"
retry
end
Can you think of any other Errors to protect and retry against? Is this a well structured way to handle errors? What are some design implementations I should consider?

Consider having a catch-all exception handler at the end that logs what kind of exception was encountered and re-raises it. Your script may fail the first time, but at least you'll find out why.
begin
# My (omitted) very long ruby task
# filled with Twitter API requests
rescue Errno::ENOENT
sleep(5)
logger.info "ENOENT error - attempting to retry"
retry
rescue Errno::ETIMEDOUT
sleep(5)
logger.info " Operation timed out - attempting to retry"
retry
rescue Errno::ECONNRESET
sleep(5)
logger.info "Connection reset by peer - attempting to retry"
retry
rescue # This rescues StandardError and its children
sleep(5)
# The next line is somewhat pseudocode, because I don't use logger
logger.this_is_somewhat_bad "Somewhat bad exception #{$!.class} #{$!} happened - I'm giving up"
raise
rescue Exception
sleep(5)
# The next line is somewhat pseudocode, because I don't use logger
logger.omg_wtf_bbq "Really bad exception #{$!.class} #{$!} happened - I'm giving up"
raise
end

I also catch the Twitter::Forbidden error in my code that uses the Twitter gem.

Alternatively, you could try rescue SystemCallError, since all Errno errors are subclasses of that.

Related

Capture failures when using Ruby open3 standard library

I'm running an external command using the Open3.popen2e function. The external command fails spectacularly halfway through. Unfortunately this also kills my ruby process that is using popen2e. What is the reason, and how can I avoid?
begin
Open3.popen2e("node mynode.js") do |i, oe|
oe.each do |ln|
puts ln.chomp
end
end
rescue => exception
puts exception.message
end
Using ruby 2.5.1 on Ubuntu
Not sure about the reason, but a non-StandardError may be raised. So, what about changing your rescue to:
rescue Exception => exception
That may give you more clues as to what is happening.

Escape Mechinze Error in Ruby Scraping

I am getting the following server response error while trying to scrape SERP results:
/Users/*********/.rvm/gems/ruby-2.3.0/gems/mechanize-2.7.5/lib/mechanize/http/agent.rb:323:in `fetch': 503 => Net::HTTPServiceUnavailable for http://******.*****.com/sorry/index?continue=http://www.********.com/search%3Fq%3D<term1>%2B<term2> -- unhandled response (Mechanize::ResponseCodeError)
I am trying to figure out how to escape the error / exception, so that the program will continue to run instead of automatically exiting.
Like anything in Ruby it probably boils down to rescue and recover:
loop do
begin
Mechanize.do_stuff!
# Success!
break
rescue Mechanize::ResponseCodeError
# Server-side failure, so let's try again after a quick break
sleep(10)
end
end
Note the sleep(10) is there to avoid slamming the server furiously and making it malfunction even harder.

Ruby Programming: 'gets' execution expired Timeout.timeout error

I have constructed a very simple Ruby program whilst exploring the Timeoutmodule, using this site as a guide.
print "\nEnter Input:"
require 'timeout'
Timeout::timeout(5) do
input = gets.chomp
end
print "\nEXITING\n"
When I run the script, it prompts the user for input, however after 5 seconds, instead of simply printing "EXITING" and promptly terminating as it logically should, it instead crashes, returning the error:
'gets': execution expired (Timeout::Error)
I am wondering why this is, and how this error could be avoided whilst the script waits for user input for 5 seconds before terminating regardless.
Thanks in advance.
Please see the documentation for the Module Timeout
It clearly states that it performs an operation in a block, raising an error if it takes longer than sec seconds to complete.
To get your desired output, you can use a rescue block to rescue the Timeout::Error and then show your EXITING message:
require 'timeout'
print "\nEnter Input:"
begin
Timeout::timeout(5) do
input = gets.chomp
end
rescue Timeout::Error => e
print "\nEXITING\n"
end

Equivalent to Perl's END block in Ruby

Is there a Perl equivalent END block in Ruby? In Perl, if I specify an END block, the code in that block will get executed no matter where the program bails out. It is great functionality for closing open file handles. Does Ruby support similar functionality? I tried Ruby's "END{}" block but that doesnt seem to get called if I had an exit in the code due to an error.
Thanks!
Use at_exit, which will run regardless of whether an exception was raised or not:
at_exit { puts 'exited!' }
raise
prints "exited" as expected.
You should only consider this if you cannot use an ensure, as at_exit causes logic to reside far away from where the actual exit occurs.
Yes. A block may have an 'ensure' clause. Here's an example:
begin
# This will cause a divide by zero exception
puts 3 / 0
rescue Exception => e
puts "An error occurred: #{e}"
ensure
puts "I get run anyway"
end
Running this produces:
An error occurred: divided by 0
I get run anyway

How to rescue from a require "gem_name" when the gem is not installed

I'm writing a library that depend on a specific gem. I require the gem and use it in my code and everything is hunky-dory as long as the gem is installed on the user's machine. but what if it is not?!
I thought it's fine cause I can rescue from the require command and print a message to the output to inform the user about the lacking gem and finish it gracefully but I get an error!
Could you tell me how it should be done or what is wrong with this piece of code:
begin
require "some_gem"
rescue
puts "please install some_gem first!"
end
require raises a LoadError exception if it can't load the required library. However, you never rescue from LoadError anywhere, you rescue from StandardError.
If you want to rescue from LoadError, you have to say so:
begin
require 'some_gem'
rescue LoadError
puts 'please install some_gem first!'
end
Even better yet, make sure that you are actually printing the correct missing dependency:
begin
require 'some_gem'
rescue LoadError => e
raise unless e.message =~ /some_gem/
puts 'please install some_gem first!'
end
(This re-raises the exact same exception that was rescued from, in case that the exception was actually caused by some other missing library somewhere else. You wouldn't want to print misleading information, right?)
Depending on what the intended target audience for the library is and whether or not they might be scared away by a backtrace being dumped to their console, you might want to re-raise the exception in any case, instead of just swallowing it:
begin
require 'some_gem'
rescue LoadError => e
puts 'please install some_gem first!' if e.message =~ /some_gem/
raise
end
Or, you could skip the puts and instead raise an exception with the message set to what you want to say:
begin
require 'some_gem'
rescue LoadError => e
raise e.exception('please install some_gem first!') if e.message =~ /some_gem/
raise
end
Except now the exception is raised in the wrong place and thus has the wrong line number and stacktrace and thus is misleading, but that is easily fixed:
begin
require 'some_gem'
rescue LoadError => e
raise unless e.message =~ /some_gem/
friendly_ex = e.exception('please install some_gem first!')
friendly_ex.set_backtrace(e.backtrace)
raise friendly_ex
end
Now you print pretty much the same thing that you would have printed with the puts, but you have a "proper" exception that for example allows better debugging or allows a consumer of your library to rescue that exception and handle it their way, both of which would have been impossible or at least hard with your solution that just swallows the exception.
begin
require "some_gem"
rescue LoadError
puts "message"
end

Resources