asynchro¶ ↑
This is a set of extensions for event-driven, asynchronous Ruby applications and improved support for testing within the EventMachine engine.
The two primary components are:
-
A simple tracker that can be used to organize multiple independent blocks and ensure that they are all completed before moving on.
-
A simple state machine defining tool that can be used to map out the steps required to complete an operation. This is especially useful if the process will vary depending on certain conditions.
Installation¶ ↑
Using the gem installation tool is the easiest way to get started:
gem install asynchro
If you’re using it within a bundler managed project, add to your Gemfile:
gem 'asynchro'
Using Asynchro::State
¶ ↑
To define a state mapping, include the Asynchro::Extensions
methods and then use the ‘async_state` method:
include Asynchro::Extensions ran = [ ] async_state do |state| state.start do ran << :start state.state1! end state.state1 do ran << :state1 state.state2! end state.state2 do ran << :state2 state.state3! end state.state3 do ran << :state3 state.finish! end state.finish do ran << :finish end end
At the end of this, the ‘ran` array will contain a list of all the states which have executed, which in this example will be all of them in order.
The two pre-defined states are ‘start` and `finish`, where the default behavior is to simply finish when started.
To declare a state, simply name it and supply a block to execute when in that particular state. Generally the ‘start` state is defined first in order to provide an entry point. The `finish` state is optional.
To transition to another state from within a state, call the name of the state with the exclamation at the end, so for ‘finish` then `finish!` would be called. Entering a state that has not been previously defined will result in a warning being sent to STDERR for diagnostic purposes.
If this warning is undesirable, declare the state with an empty block.
Be careful to avoid entering states for which there is no exit condition or the execution will never successfully complete.
Using Asynchro::Tracker
¶ ↑
The tracker component is used to process multiple blocks independently, yet confirm that they have all completed before moving on. This control structure helps to avoid duplicating logic in callback methods.
A simple example is:
require 'rubygems' gem 'asynchro' require 'asynchro' include Asynchro::Extensions def example_async_call yield end success = false async_tracker do |tracker| tracker.perform do |done| example_async_call do done.call end end tracker.perform(4) do |done| example_async_call do done.call end end tracker.finish do success = true end end
The main ‘async_tracker` call will appear to block until all of the actions defined by `perform` are completed. More specifically, the `done` trigger must be called in order to carry forward. Generally this trigger is passed through to the final block that must be executed before the operation is completed. In this example the trigger is scoped such that the inner block has access to it.
The ‘perform` method is used to declare something that must be performed, and the `finish` method will be executed once all of the declared blocks have executed their callback.
The ‘perform` method takes a numerical argument that indicates the number of times the callback must be called in order to be completed. The default is 1. Negative or zero values will result in undefined behavior.
It is possible to declare ‘perform` blocks at any time prior to the completion of the last block. This enables additional processing to be performed only if certain requirements are met, or for actions to be chained together as required.
Just as multiple ‘perform` blocks can be declared, multiple `finish` blocks can be supplied. These will execute in the order they are defined, once, upon completion of all the prerequisite blocks.
As there is no timeout, the tracker will wait for an indefinite period of time if something precludes one or more of the callbacks from being executed. This tracker is only suitable for asynchronous code that is designed such that it will always trigger a callback of some sort within an acceptable period of time.
Other Notes¶ ↑
Additional demonstrations of these are included in the test/ directory.
Copyright¶ ↑
Copyright © 2011-2012 Scott Tadman, The Working Group Inc. See LICENSE.txt for further details.