Can ruby exceptions be handled asynchronously outside of a Thread::handle_interrupt block? Can ruby exceptions be handled asynchronously outside of a Thread::handle_interrupt block? multithreading multithreading

Can ruby exceptions be handled asynchronously outside of a Thread::handle_interrupt block?


Ruby provides for this with the ruby Queueobject (not to be confused with an AMQP queue). It would be nice if Bunny required you to create a ruby Queue before opening a Bunny::Session, and you passed it that Queue object, to which it would send connection-level errors instead of using Thread#raise to send it back to where ever. You could then simply provide your own Thread to consume messages through the Queue.

It might be worth looking inside the RabbitMQ gem code to see if you could do this, or asking the maintainers of that gem about it.

In Rails this is not likely to work unless you can establish a server-wide thread to consume from the ruby Queue, which of course would be web server specific. I don't see how you can do this from within a short-lived object, e.g. code for a Rails view, where the threads are reused but Bunny doesn't know that (or care).


I'd like to raise (ha-ha!) a pragmatic workaround. Here be dragons. I'm assuming you're building an application and not a library to be redistributed, if not then don't use this.

You can patch Thread#raise, specifically on your session thread instance.

module AsynchronousExceptions  @exception_queue = Queue.new  class << self    attr_reader :exception_queue  end  def raise(*args)    # We do this dance to capture an actual error instance, because    # raise may be called with no arguments, a string, 3 arguments,    # an error, or any object really. We want an actual error.    # NOTE: This might need to be adjusted for proper stack traces.    error = begin      Kernel.raise(*args)    rescue => error      error    end    AsynchronousExceptions.exception_queue.push(error)  endendsession_thread = Thread.currentsession_thread.singleton_class.prepend(AsynchronousExceptions)

Bear in mind that exception_queue is essentially a global. We also patch for everybody, not just the reader loop. Luckily there are few legitimate reasons to do Thread.raise, so you might just get away with this safely.