As @maniacalrobot said, using EM.defer/deferrable
lets the procs be run without blocking the reactor.
But then you enter "callback hell" when you need to run several procs serially.
I know two solutions to make the code more readable: promises and fibers.
Promises gives you a nice API to compose asynchronous calls, there are a lot of good articles out there, including:
- http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/
- http://www.html5rocks.com/en/tutorials/es6/promises/
Fibers are a more ruby specific tool which makes your code look synchronous while doing asynchronous things.
Here is an helper method to execute a proc asynchronously (deferred) but still block the calling code without blocking the main reactor (that's the magic of Fibers):
def deferring(action)
f = Fiber.current
safe_action = proc do
begin
res = action.call
[nil, res]
rescue => e
[e, nil]
end
end
EM::defer(safe_action, proc { |error, result| f.resume([error, result]) })
error, result = Fiber.yield
raise error if error
result
end
Example of usage:
action1_res = deferring(proc do
puts 'Async action 1'
42
end
begin
deferring(proc do
puts "Action1 answered #{action1_res}"
raise 'action2 failed'
end)
rescue => error
puts error
end