Handling exceptions raised in a Ruby thread Handling exceptions raised in a Ruby thread multithreading multithreading

Handling exceptions raised in a Ruby 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 thisdef foo(n)    puts " for #{n}"    sleep n    raise "after #{n}"endbegin    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 15EXCEPTION: #<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    }  endend


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  endendputs :startbegin  thread = SafeThread.new do    raise 'error from sub-thread'  end  puts 'do something heavy before joining other thread'  sleep 1  thread.joinrescue Exception => e  puts "Caught: #{e}"endputs 'proper end'