await¶ ↑
This implements the await/defer pattern in Ruby using fibers within the EventMachine environment.
In general terms, await
is used to define a group of operations that must be completed before processing can continue, and defer
is used to define these individual operations.
This can be used to simplify otherwise complicated callback structures where a number of operations can be performed in parallel. Further complexity arises when some of these operations have optional steps.
Examples¶ ↑
In order to execute properly, an await
call must be created within a fiber that can yield. Since the root fiber cannot yield, a secondary fiber must be created.
A very simple example shows how a number of timers can be set to simulate some long-running asynchronous operations:
require 'await' require 'eventmachine' EventMachine.run do Fiber.new do include Await now = Time.now await do EventMachine::Timer.new(5, &defer) EventMachine::Timer.new(2, &defer) EventMachine::Timer.new(3, &defer) end puts "Took %.1fs to complete" % (Time.now - now).to_f EventMachine.stop_event_loop end.resume end
In the end you should see that it took only as long as the longest timer.
In its default state, defer
is simply used as a trigger. It can also wrap around a callback block to add additional functionality:
require 'await' require 'eventmachine' EventMachine.run do Fiber.new do include Await now = Time.now await do trigger = defer do |x, y| puts "Received arguments: #{[ x, y ].inspect}" end EventMachine::Timer.new(4) do trigger.call(1, '2') end EventMachine::Timer.new( 3, &defer do EventMachine::Timer.new( 2, &defer ) end ) end puts "Took %.1fs to complete" % (Time.now - now).to_f EventMachine.stop_event_loop end.resume end
Since the defer
method returns a standard Proc callback, it is possible to pass it through as a callback method or to trigger it at an arbitrary time with call
.
More examples of callback structures are available in the various unit tests.
Troubleshooting¶ ↑
If the secondary fiber has not been created you will see errors like:
FiberError: can't yield from root fiber
Keep in mind that unless a defer
call is made within a callback then the operation is considered completed. If an additional asynchronous operation must be performed before it is complete, be sure to wrap any and all of these calls with defer
as well to tag and track them properly.
Copyright¶ ↑
Copyright © 2012 Scott Tadman, The Working Group Inc. See LICENSE.txt for further details.