socketry / async

An awesome asynchronous event-driven reactor for Ruby.
MIT License
2.12k stars 86 forks source link

Unhandled Exception does not stop program running #260

Closed jsaak closed 1 year ago

jsaak commented 1 year ago

Unhandled Exception does not stop program running:

(does work when uncommenting Fiber.schedule do)

require 'async'

Fiber.set_scheduler(Async::Scheduler.new)

class X
  def set_callback(&block)
    @block = block
  end

  def run_callback
    @block.call
  end

  def run
    Fiber.schedule do
      loop do
        puts 1
        sleep 1
      end
    end
  end
end

#Fiber.schedule do
  x = X.new
  x.set_callback do
    puts 3
    asdf
    puts 4
  end

  x.run
  sleep 1
  puts 2
  x.run_callback
#end
ioquatix commented 1 year ago

This is probably a bug that can only be fixed by modifying/fixing CRuby.

It's probably in the thread exit code path where a scheduler is set, it's ignoring the exception.

I'll take a look.

ioquatix commented 1 year ago

As a bit of a hack, we can define Async::Scheduler#scheduler_close as:

        def scheduler_close
            unless $!
                self.run
            end
        ensure
            self.close
        end

and it works as you expect, but I don't like using the implicit $! exception reference. We should probably pass it explicitly if possible.

ioquatix commented 1 year ago

I'm basically okay with the proposed fix, the chance of $! being set incorrectly in the scheduler_close context is probably zero.

ioquatix commented 1 year ago

This should be fixed, please feel free to test it and report back.

jsaak commented 1 year ago

Either this fix or the scheduler closing broke exception handling for me: I can not catch exception any more in Fibers.

/home/jsaak/.gem/ruby/3.2.2/gems/async-2.6.3/lib/async/scheduler.rb:246:in `select': Failed (RuntimeError)
    from /home/jsaak/.gem/ruby/3.2.2/gems/async-2.6.3/lib/async/scheduler.rb:246:in `run_once!'
    from /home/jsaak/.gem/ruby/3.2.2/gems/async-2.6.3/lib/async/scheduler.rb:222:in `run_once'
    from /home/jsaak/.gem/ruby/3.2.2/gems/async-2.6.3/lib/async/scheduler.rb:285:in `block in run'
    from /home/jsaak/.gem/ruby/3.2.2/gems/async-2.6.3/lib/async/scheduler.rb:279:in `handle_interrupt'
    from /home/jsaak/.gem/ruby/3.2.2/gems/async-2.6.3/lib/async/scheduler.rb:279:in `run'
    from /home/jsaak/.gem/ruby/3.2.2/gems/async-2.6.3/lib/async/scheduler.rb:46:in `scheduler_close'
jsaak@auto:[master]~$ curl: (23) Failure writing output to destination
(23) Failed writing body
curl: (23) Failure writing output to destination

After this happens, it hangs. Does not exit.

I do not understand what you are trying to do.

ioquatix commented 1 year ago

Do you mind giving me a small reproduction?

jsaak commented 1 year ago

I will try.

jsaak commented 1 year ago

For me all problems started with stopping the event loop. There is a trick used by many without OS interrupts. Make a pipe. And select() on the read end of the pipe all the time. And if you want to interrupt, then you write a byte to the write end of the pipe. Maybe it is completely unrelated, but i hope this may help you.

jsaak commented 1 year ago

It is all good. I am sorry for the false alarm. This time it was an error on my side. (Sent an exception to the wrong fiber, where there was no exception handling)

ioquatix commented 1 year ago

It's all good, let me know if you run into any other issues.