This is sample code which i am trying to handle exception from unicorn.
unicron.rb
worker_processes Integer(ENV['WEB_CONCURRENCY'] || 3)
timeout 15
preload_app true
timeout.rb
Rack::Timeout.timeout = 12
Sample code
def create_store
ActiveRecord::Base.transaction do
#store = Store.new(params[:store])
if #store.save!
sleep 12.3
InformUserWorker.perform_async(store_id)
end
end
rescue => exception
exception.backtrace.each { |trace| puts trace }
rescue Timeout::Error
puts 'That took too long, exiting...1'
rescue Rack::Timeout::RequestTimeoutException
puts 'That took too long, exiting...2'
rescue Rack::Timeout::RequestTimeoutError
puts 'That took too long, exiting...3'
rescue Rack::Timeout::RequestExpiryError
puts 'That took too long, exiting...4'
end
I am getting code=H13 desc="Connection closed without response" with this sleep 12.3 seconds, and the transaction rollback happens, but none of these exceptions are executing. I have added couple of exception here. Anything goes wrong here?.
Rescues are executed in order. So your first rescue captures anything that is being raised and the code never gets past that point.
Try putting it last:
# other rescues in here.
rescue => exception
exception.backtrace.each { |trace| puts trace }
end # this one is the last, only executed if none of the others are
If the problem is that you're not sure which class is being raised, just use something like pry to debug the exception.class
Related
I have the following code in Rails routing:
class LegacyRedirector
InvalidUrlError = Class.new(ActionController::RoutingError)
def call(params, request)
URI.parse(request.path)
rescue URI::InvalidURIError => e
raise InvalidUrlError.new(e.message)
end
end
# routes.rb
match 'a', to: redirect(LegacyRedirector.new)
This is for catching invaild URLs. However when I test it in browser for curl, it would still display URI::InvalidURIError, not my new error class. It seems the rescue block was never reached, yet I am sure I am rescuing the correct type. How can that be?
URI::InvalidURIError at /twitter/typeahead-js/wikis/home[
=========================================================
> bad URI(is not URI?): "/twitter/typeahead-js/wikis/home["
lib/gitlab/routing.rb, line 31
------------------------------
``` ruby
> 31 URI.parse(request.path)
32 rescue URI::InvalidURIError => e
33 raise InvalidUrlError.new(e.message)
34 end
```
One possible cause could be better_errors.
If an error is raised in a rescue block, its cause would be the original error. better_errors displays that cause instead, meaning the backtrace will not be in the rescue block. This gives you the illusion that it is never rescued.
This was recently fixed, see https://github.com/BetterErrors/better_errors/pull/459 for more details
I have a rake task that loops through rows in CSV file, and inside that loop, there's a begin/rescue block to catch any possible raised exception. But when I run it, it keeps on saying 'rake aborted!' and it is not entering the rescue block
CSV.foreach(path, :headers => true) do |row|
id = row.to_hash['id'].to_i
if id.present?
begin
# call to mymethod
rescue => ex
puts "#{ex} error executing task"
end
end
end
...
def mymethod(...)
...
begin
response = RestClient.post(...)
rescue => ex
raise Exception.new('...')
end
end
Expected: It should finish looping all the rows of the CSV
Actual result: It stops after reaching the 'raise' exception saying that:
rake aborted!
Exception: error message here
...
Caused by:
RestClient::InternalServerError: 500 Internal Server Error
You can use next to skip the faulty step of loop:
CSV.foreach(path, :headers => true) do |row|
id = row.to_hash['id'].to_i
if id.present?
begin
method_which_doing_the_staff
rescue SomethingException
next
end
end
end
And raise the exception inside your method:
def method_which_doing_the_staff
stuff
...
raise SomethingException.new('hasd')
end
I solved this issue by just commenting out the line that is raising an exception because it seems like it the quickest fix for now.
# raise Exception.new('...')
I'm still open to other suggestions if there are any better ways to do it.
I keep getting this error (without any backtrace) in my production logs:
!!! ERROR HANDLER THREW AN ERROR !!!
For my understanding that means that a registered error handler is raising an exception.
However my application doesn't have any custom error handler.
How can I debug / solve this issue?
My application looks like this:
class DeliveryJob
include Sidekiq::Worker
sidekiq_options queue: :deliveries, retry: 3
sidekiq_retry_in { |count| 20 * (3 ** count) }
sidekiq_retries_exhausted do |s|
# do something (some methods use Redis) ...
Rails.logger.tagged('delivery') do
Rails.logger.error "Sidekiq retries exhausted for ..."
end
end
def perform(id)
Notification.find(id).deliver
end
end
class Notification
def deliver
# do something that may fail
rescue => e
Rails.logger.tagged('delivery') do
Rails.logger.error "Delivery error for #{endpoint}: #{e.to_s}"
end
raise e
end
end
So in my logs I often see something like:
Delivery error for https://example.com/path: SSL connection error, etc.
Followed by:
!!! ERROR HANDLER THREW AN ERROR !!!
The Delivery error is ok and expected, however I don't understand why I get an error from an error handler.
https://github.com/mperham/sidekiq/blob/d8f11c26518dbe967880f76fd23bb99e9d2411d5/lib/sidekiq/exception_handler.rb#L23
Sidekiq throws this error from its own error handler.
I'm trying to figure out the best way to catch a specific error thrown AND the error's message in Ruby on Rails. My use case is that I encounter a timeout error every now and then which is thrown with a general error and I want to treat the timeout error differently than other errors within the same general error. I'm not sure what other type of errors could be thrown in the general error but I assume more of them exist. I have some sample code below of how I'm currently handling it, but I was thinking there might be a better way which I haven't found yet?
tries = 0
begin
tries += 1
<code>
rescue Foo::Bar => e
case e.to_s
when 'More specific timeout error message'
retry unless tries >= 5
else
# Let me see other error messages
log.info("Error: #{e.to_s}")
end
end
You can use multi rescue, to handle different errors.
begin
# DO SOMETHING
rescue Net::Timeout => e # change it to the error your want to catch, check the log.
# handle it
rescue SyntaxError => e # just an example
# handle it
rescue => e # any error that not catch by above rescue go here.
# handle it
end
Read more:
http://phrogz.net/programmingruby/tut_exceptions.html
You can try Rollbar, it help report error on production.
Take a look at retriable gem. It seems like a good fit for what you're proposing. Usually you'd rescue from an specific error type, but retriable also gives you the choice to rescue based on the error message.
begin
Retriable.retriable on: { Foo::Bar => /More specific timeout error message/ }, tries: 3 do
# will retry if an error of type Foo::Bar is raised
# and its message matches /More specific timeout error message/
# code here...
end
rescue => e # rescue for everything else
puts e.message # same as e.to_s
end
I use 'rubyoverflow' gem in rails:
begin
puts "=== 1 ==="
qt = Questions.retrieve_by_tag(tag).questions
puts "=== 2 ==="
rescue
puts "=== 3 ==="
end
But sometimes I get the error on the console:
couldn't parse YAML at line 843 column 4
C:/Ruby192/lib/ruby/1.9.1/psych.rb:148:in parse'
C:/Ruby192/lib/ruby/1.9.1/psych.rb:148:inparse_stream' ... rubyoverflow
(1.0.1) lib/rubyoverflow.rb:86:in request' ...
C:/Ruby192/lib/ruby/1.9.1/webrick/server.rb:183:inblock in start_thread'
But the question not about the error in the gem, but about the exception handling. I get in the console only line:
puts "=== 1 ==="
but not lines
puts "=== 2 ==="
puts "=== 3 ==="
why?
How can I restore esecution of my program if the line
qt = Questions.retrieve_by_tag(tag).questions
fails?
By default rescue traps StandardError and whatever inherits from it.
From the docs:
By default, rescue only intercepts StandardError and its descendants...
The exception being raised is probably not that, so rescue doesn't handle it.
Usually you can figure out what to use as rescue's parameter from the docs to the method raising it, but, if not, you can use
rescue Exception => e
print e.to_s
end
to see what the exception is, then replace Exception with that value.
More information is on the internet, but here's a piece of code to print a list of Exceptions.