How to catch raised exception in rake task - ruby-on-rails

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.

Related

Not catching the unicorn timeout exception in rails

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

Keep data if transaction fails?

I've got a transaction which needs detailed logging, even if it fails. How can I do that?
This is my code:
# csv gets loaded etc.
import = CsvImport.new
import.logger += 'Starting import'
ActiveRecord::Base.transaction do
import.logger += 'CSV loaded, starting import'
csv_array.each_with_index do |row, index|
begin
unless importer.has_key?(row[0])
import.logger += 'Key not found'
raise StandardError
end
result = CsvImporter.import_line(row[0])
import.logger += 'Imported line #{index} successfully' if result
rescue
import.logger += 'Transaction aborted!'
end
end
import.logger += 'Transaction successful!'
end
In a failed transaction, the logger only has "Starting import" without any of the added strings inside the transaction - obviously. How can I keep that data?
The begin-rescue block is just a wrapper to catch exceptions. In your case you need, like you said, a transaction. You can use something like this
YourClass.transaction do
# do a lot of stuff
end
or
#yourmodel.transaction do
# do stuff !
end
Look at the docs: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
A combination of transaction and rescue block are possible: Look at the docs at section "Exception handling and rolling back"

Rails rake task invoke error catching

I have a rails code snippet that does a rake file from a model.
Rake.application.rake_require '../../lib/tasks/master_load'
fork do
results = capture_stdout {Rake.application['db:seed:excel:to_yaml'].invoke}
end
capture_stdout is for printing out the logs
def self.capture_stdout
s = StringIO.new
oldstdout = $stdout
$stdout = s
yield
s.string
Rails.logger.info "#{s.string}"
ensure
$stdout = oldstdout
end
it works, but when the rake encounters error and fails.
it fails silently.
is there a way to know if error has occured and perhaps get the error log?
Use rescue to catch and handle error
def self.capture_stdout
s = StringIO.new
oldstdout = $stdout
$stdout = s
yield
s.string
Rails.logger.info "#{s.string}"
rescue Exception => e
# handle e - exception object
ensure
$stdout = oldstdout
end
Ensure in this case silently makes action after exception handling

How to suppress backtrace in Rails?

When exiting a Rails app using raise or fail, how to prevent the backtrace from being displayed?
Tried using back_trace_limit but it only seems to work for the console...?
You have total control over the backtrace returned with an exception instance by using its set_backtrace method. For example:
def strip_backtrace
yield
rescue => err
err.set_backtrace([])
raise err
end
begin
strip_backtrace do
puts 'hello'
raise 'ERROR!'
end
rescue => err
puts "Error message: #{err.message}"
puts "Error backtrace: #{err.backtrace}"
end
Output:
hello
Error message: ERROR!
Error backtrace: []
The strip_backtrace method here catches all errors, sets the backtrace to an empty array, and re-raises the modified exception.

Resque error- wrong number of arguments(0 for 1)

I am using rescue to handle all the heavy lifting background tasks,
In my library/parsers/file.rb I have
Resque.enqueue(Hello)
This will redirect app/workers/file.rb where I have
class Hello
def self.perform(page)
.......
.......
end
rescue Exception => e
log "error: #{e}"
end
end
my lib/tasks/resque.rake file is
require "resque/tasks"
task "resque:setup" => :environment
I am able to queue the jobs buts when i try to execute the job using
rake resque:work QUEUE=*
it is throwing an error by saying
argument error
wrong number of arguments (0 for 1)
what am I doing wrong in this?
pjumble is exactly right, you're not passing the page.
Resque.enqueue(Hello, page_id)
enqueue takes the Job followed by the args which go into the perform action. If you had:
class Hello
def self.perform(page_number, page_foo, page_bar)
...
end
end
Then you would do this:
Resque.enqueue(Hello, page_number, page_foo, page_bar)

Resources