How to resume from rescue clause in Ruby? - ruby

How can I write resuming into loops in Ruby? Here is a sample code.
#!/usr/bin/ruby
#
a = [1,2,3,4,5]
begin
a.each{|i|
puts i
if( i==4 ) then raise StandardError end # Dummy exception case
}
rescue =>e
# Do error handling here
next # Resume into the next item in 'begin' clause
end
However, when running, Ruby returns the error message
test1.rb:13: Invalid next
test1.rb: compile error (SyntaxError)
I'm using Ruby 1.9.3.

You should use retry instead of next; But this will cause infinite loop (retry restart from the beginning of the begin)
a = [1,2,3,4,5]
begin
a.each{|i|
puts i
if i == 4 then raise StandardError end
}
rescue =>e
retry # <----
end
If you want skip an item, and continue to next item, catch the exception inside the loop.
a = [1,2,3,4,5]
a.each{|i|
begin
puts i
if i == 4 then raise StandardError end
rescue => e
end
}

Move your exception catching into the each block e.g:
a = [1,2,3,4,5]
a.each do |i|
puts i
begin
# Dummy exception case
if( i==4 ) then raise StandardError end
rescue =>e
# Do error handling here
end
end

Related

Ruby, catching library thread exceptions?

I'm using a gem that's throwing an exception in a background thread as below. I'd like to catch this exception but not sure about how to go about it. How would one go about handling exceptions in library threads?
#this class is in my code
class MQTT
def self.connect
#client = Client.connect(options)
end
ende
This class is in the library which is packaged as a gem, so I technically don't have access to it:
class Client
def self.connect(*args, &block)
client = Client.new(*args)
client.connect(&block)
return client
end
def connect(clientid=nil)
# Start packet reading thread
#read_thread = Thread.new(Thread.current) do |parent|
Thread.current[:parent] = parent
loop { receive_packet }
end
end
def receive_packet
begin
# Poll socket - is there data waiting?
result = IO.select([#socket], nil, nil, SELECT_TIMEOUT)
# Pass exceptions up to parent thread
rescue Exception => exp
unless #socket.nil?
#socket.close
#socket = nil
end
Thread.current[:parent].raise(exp)
end
end
end
I think you have 3 options.
You could return the exception to the calling thread:
def receive_packet
raise "Exception in #{Thread.current}"
rescue Exception => exp
return exp
end
t1 = Thread.new do
receive_packet
end
puts "t1: #{t1.value.inspect}"
You could catch the exception on joining the thread (note you could reraise here or use an ensure block to make sure your socket is closed):
def receive_packet
raise "Exception in #{Thread.current}"
rescue Exception => exp
# reraise the exception
raise exp
end
t = Thread.new do
receive_packet
end
begin
t.join
rescue => e
puts "Exception caught from joined thread #{e.message} "
end
or you set #abort_on_exception = true so that exceptions kill all threads:
Thread.abort_on_exception = true
begin
Thread.new do
receive_packet
end
sleep 1
rescue => e
puts "Exception raised immediately to main thread: #{e.message}"
end
Update Based on what you have above and your comment I guess you need to wait for the threads calling receive_packet to finish. So you would have to join them:
class Client
def self.connect(*args, &block)
client = Client.new(*args)
client.connect(&block)
return client
end
def initialize(args)
#count = 0
end
def connect(clientid=nil)
puts "Connecting. Thread.current is #{Thread.current}"
# Start packet reading thread
#read_thread = Thread.new(Thread.current) do |parent|
Thread.current[:parent] = parent
loop { receive_packet }
end
end
def receive_packet
begin
# Poll socket - is there data waiting?
# result = IO.select([#socket], nil, nil, SELECT_TIMEOUT)
sleep 0.1
#count += 1
puts "count is now #{#count}"
if #count == 3
raise "WOOT: #{#count}"
end
# Pass exceptions up to parent thread
rescue Exception => exp
unless #socket.nil?
#socket.close
#socket = nil
end
puts "Reraising error #{exp.inspect} from #{Thread.current} to #{Thread.current[:parent]}"
Thread.current[:parent].raise(exp)
end
end
end
class MQTT
def self.connect
#client = Client.connect(options = {})
end
end
begin
MQTT.connect
Thread.list.each do |t|
# Wait for the thread to finish if it isn't this thread (i.e. the main thread).
t.join if t != Thread.current
end
rescue => e
puts "Exception from child thread: #{e.inspect}"
end

What is invalid next in Ruby?

The following code works:
collection.each do |i|
begin
next if i > 10
i += 1
rescue
puts "could not process #{ i }"
end
end
However, when we refactor:
collection.each do |i|
begin
increment i
rescue
puts "could not process #{ i }"
end
end
def increment i
next if i > 10
i += 1
end
I get invalid next error. Is this a limitation of Ruby (1.9.3)?
Does the begin rescue block work the same way if there is an exception in the increment method?
Your next statement must occur inside a loop. There's no loop inside your increment method.
Exceptions will 'bubble up', so if there's an exception in your increment method, it will be caught by the rescue section of the calling method.

Handling exceptions raised in a Ruby thread

I am looking for a solution of classic problem of exception handling. Consider following piece of code:
def foo(n)
puts " for #{n}"
sleep n
raise "after #{n}"
end
begin
threads = []
[5, 15, 20, 3].each do |i|
threads << Thread.new do
foo(i)
end
end
threads.each(&:join)
rescue Exception => e
puts "EXCEPTION: #{e.inspect}"
puts "MESSAGE: #{e.message}"
end
This code catches the exception after 5 seconds.
But if I change the array as [15, 5, 20, 3], above code catch the exception after 15 seconds. In short, it always catch the exception raised in first thread.
Any idea, why so. Why doesn't it catch the exception after 3 seconds each time? How do I catch the first raised exception by any thread?
If you want any unhandled exception in any thread to cause the interpreter to exit, you need to set Thread::abort_on_exception= to true. Unhandled exception cause the thread to stop running. If you don't set this variable to true, exception will only be raised when you call Thread#join or Thread#value for the thread. If set to true it will be raised when it occurs and will propagate to the main thread.
Thread.abort_on_exception=true # add this
def foo(n)
puts " for #{n}"
sleep n
raise "after #{n}"
end
begin
threads = []
[15, 5, 20, 3].each do |i|
threads << Thread.new do
foo(i)
end
end
threads.each(&:join)
rescue Exception => e
puts "EXCEPTION: #{e.inspect}"
puts "MESSAGE: #{e.message}"
end
Output:
for 5
for 20
for 3
for 15
EXCEPTION: #<RuntimeError: after 3>
MESSAGE: after 3
Note: but if you want any particular thread instance to raise exception this way there are similar abort_on_exception= Thread instance method:
t = Thread.new {
# do something and raise exception
}
t.abort_on_exception = true
Thread.class_eval do
alias_method :initialize_without_exception_bubbling, :initialize
def initialize(*args, &block)
initialize_without_exception_bubbling(*args) {
begin
block.call
rescue Exception => e
Thread.main.raise e
end
}
end
end
Postponed exceptions processing (Inspired by #Jason Ling)
class SafeThread < Thread
def initialize(*args, &block)
super(*args) do
begin
block.call
rescue Exception => e
#exception = e
end
end
end
def join
raise_postponed_exception
super
raise_postponed_exception
end
def raise_postponed_exception
Thread.current.raise #exception if #exception
end
end
puts :start
begin
thread = SafeThread.new do
raise 'error from sub-thread'
end
puts 'do something heavy before joining other thread'
sleep 1
thread.join
rescue Exception => e
puts "Caught: #{e}"
end
puts 'proper end'
This will wait for the first thread to either raise or return (and re-raise):
require 'thwait'
def wait_for_first_block_to_complete(*blocks)
threads = blocks.map do |block|
Thread.new do
block.call
rescue StandardError
$!
end
end
waiter = ThreadsWait.new(*threads)
value = waiter.next_wait.value
threads.each(&:kill)
raise value if value.is_a?(StandardError)
value
end
Jason Ling's answer will miss out any arguments passed to Thread.new. This will break Puma and other gems. To avoid this problem, you can use:
Thread.class_eval do
alias_method :initialize_without_exception_bubbling, :initialize
def initialize(*args, &block)
initialize_without_exception_bubbling(*args) {
begin
block.call(*args)
rescue Exception => e
Thread.main.raise e
end
}
end
end

ruby: how to know if script is on 3rd retry?

begin
#some routine
rescue
retry
#on third retry, output "no dice!"
end
I want to make it so that on the "third" retry, print a message.
Possibly not the best solution, but a simple way is just to make a tries variable.
tries = 0
begin
# some routine
rescue
tries += 1
retry if tries <= 3
puts "no dice!"
end
loop do |i|
begin
do_stuff
break
rescue
raise if i == 2
end
end
or
k = 0
begin
do_stuff
rescue
k += 1
k < 3 ? retry : raise
end
begin
#your code
rescue
retry if (_r = (_r || 0) + 1) and _r < 4 # Needs parenthesis for the assignment
raise
end
There is another gem named retry-this that helps with such a thing.
ruby-1.9.2-p0 > require 'retry-this'
ruby-1.9.2-p0 > RetryThis.retry_this(:times => 3) do |attempt|
ruby-1.9.2-p0 > if attempt == 3
ruby-1.9.2-p0 ?> puts "no dice!"
ruby-1.9.2-p0 ?> else
ruby-1.9.2-p0 > puts "trying something..."
ruby-1.9.2-p0 ?> raise 'an error happens' # faking a consistent error
ruby-1.9.2-p0 ?> end
ruby-1.9.2-p0 ?> end
trying something...
trying something...
no dice!
=> nil
The good thing about such a gem as opposed to raw begin..rescue..retry is that we can avoid an infinite loop or introducing a variable just for this purpose.
class Integer
def times_try
n = self
begin
n -= 1
yield
rescue
raise if n < 0
retry
end
end
end
begin
3.times_try do
#some routine
end
rescue
puts 'no dice!'
end
The gem attempt is designed for this, and provides the option of waiting between attempts. I haven't used it myself, but it seems to be a great idea.
Otherwise, it's the kind of thing blocks excel at, as other people have demonstrated.
def method(params={})
tries ||= 3
# code to execute
rescue Exception => e
retry unless (tries -= 1).zero?
puts "no dice!"
end
Proc.class_eval do
def rescue number_of_attempts=0
#n = number_of_attempts
begin
self.call
rescue => message
yield message, #n if block_given?
#n -= 1
retry if #n > 0
end
end
end
And then you can use it as:
-> { raise 'hi' }.rescue(3)
-> { raise 'hi' }.rescue(3) { |m, n| puts "message: #{m},
number of attempts left: #{n}" }

How does one use rescue in Ruby without the begin and end block

I know of the standard technique of having a begin rescue end
How does one just use the rescue block on its own.
How does it work and how does it know which code is being monitored?
A method "def" can serve as a "begin" statement:
def foo
...
rescue
...
end
You can also rescue inline:
1 + "str" rescue "EXCEPTION!"
will print out "EXCEPTION!" since 'String can't be coerced into Fixnum'
I'm using the def / rescue combination a lot with ActiveRecord validations:
def create
#person = Person.new(params[:person])
#person.save!
redirect_to #person
rescue ActiveRecord::RecordInvalid
render :action => :new
end
I think this is very lean code!
Example:
begin
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
ensure
# ensure that this code always runs
end
Here, def as a begin statement:
def
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
ensure
# ensure that this code always runs
end
Bonus! You can also do this with other sorts of blocks. E.g.:
[1, 2, 3].each do |i|
if i == 2
raise
else
puts i
end
rescue
puts 'got an exception'
end
Outputs this in irb:
1
got an exception
3
=> [1, 2, 3]

Resources