igrigorik / em-synchrony

Fiber aware EventMachine clients and convenience classes

Home Page:http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FiberIterator breaks normal exception handling

dgutov opened this issue · comments

Example (failing spec):

  it "permits normal handling of errors" do
    caught = nil

    EM.synchrony do
      begin
        EM::Synchrony::FiberIterator.new(0..1, 2).each do |num|
          raise "#{num} here"
        end
      rescue => e
        caught = e.message
      end

      EM.stop
    end

    expect(caught).to eq("0 here")
  end

The rescue block is never entered, and the only way to catch the exception is with EM.error_handler or catching it outside of the EM loop. Neither approach is composable.

@igrigorik Any ideas for an easy fix?

Right. But still, this kinda works (it outputs 3 at the end, at least):

    counter = 0

    EM.synchrony do
      f = Fiber.current

      maybe_stop = proc { f.resume if counter == 2 }

      f1 = Fiber.new do
        EM::Synchrony.sleep(1)
        counter += 1
        puts counter
        maybe_stop[]
      end

      f2 = Fiber.new do
        begin
          EM::Synchrony.sleep(1)
          counter += 1
          puts counter
          raise "aaa"
        ensure
          maybe_stop[]
        end
      end

      EM.next_tick { f1.resume }
      EM.next_tick { f2.resume }

      begin
        Fiber.yield
      ensure
        puts 3
      end
      EM.stop
    end

And this catches the error, even though it was raised in a different fiber:

    f = Fiber.new do
      raise "bar"
    end

    begin
      f.resume
    rescue
      puts "safety caught"
    end

Maybe all worker fibers should be created by the caller fiber, on the main thread.

Alas, no. The second option doesn't seem like it'll work either when one of the worker fibers is suspended and then woken by the reactor thread (which is how we handle asynchrony normally).