Search code examples
rubymultithreadingrescue

Ruby: rescue doesn't rescue from thread


Thread.abort_on_exception = true

begin
    #code in this block doesn't matter at all, it just needs to produce errors.
    [1, 2].each do |i|
        a = Thread.new do
            errory
        end
    end 
    a.join 
rescue Exception
    puts 'error!'
end

raises /home/lakesare/Desktop/multithreading/test.rb:6:in 'block (2 levels) in <main>': undefined local variable or method 'errory' for main:Object (NameError) instead of returning error! for some reason.
If Thread.new {} isn't wrapped in each {}, block is rescued properly.
Why is that? How to rescue my thread properly in this case?

edit: I found wrapping begin-rescue-end block in identical block helps. But one question lingers - why isn't one rescue enough?

edit: wrapping in another rescue block helps, but not always - sometimes it still doesn't rescue.


Solution

  • There are a few problems with what you have written that I think are clouding the issue for you.

    1. You shouldn’t set Thread.abort_on_exception = true unless you really want your program to abort when an exception occurs in a secondary thread. Typically, you’d only want this set to true for debugging. If set to false, any exception raised in a thread will cause that thread to exit but will only be visible to the parent thread when you join with the child thread.

    2. In your code above, when you attempt to join with a thread, the variable a is out of scope. Thus you should get a NameError there too.

    3. Even if this were in scope, you are only joining with one of your threads.

    You should find the following more predictable:

    Thread.abort_on_exception = false
    
    begin
      threads = [1, 2].collect do |i|
        Thread.new do
          errory
        end
      end
      threads.each { |thread| thread.join } # You might want to use a ThreadsWait here instead.
    rescue Exception
      puts 'error!'
    end