Just released version 2.3.0 of ruote, a workflow engine for Ruby.
The last release was beginning March 2011, it was the 2.2.0. Many things happened, I couldn’t find the time to release a new version, although the developement was very active. Blame it on Bundler, it makes it so easy to just point at a master branch.
It could have been released as a 2.2.1 since there are no breaking changes, but I prefer to label it 2.3.0.
What’s new in this release, what’s improved? The changelog might be a bit dry. Here are some highlights:
Participants get a new callback: on_apply. It gives an opportunity to implementers to do something with the workitem before it gets dispatched to the (real) participant.
New flanking concept: parallel workflow lanes that get cancelled as soon as the sequence they belong to finishes.
Timers are like super timeouts. They list time deltas and what’s supposed to happen at that point.
Ruote::Dashboard preferred over Ruote::Engine. To emphasize that the engine is the whole dashboard(s) + worker(s) + storage system.
A template class for observing ruote events got added: Ruote::Observer. Hartog de Mik contributed a more refined version: Ruote::ProcessObserver. Implementations of these templates can be registered in ruote and log/observe/react on workflow activity.
Now some more detailed highlights:
A 2.2.0 ruote participant would look like:
1 class Scout 2 include Ruote::LocalParticipant 3 4 def consume(workitem) 5 6 result = [ workitem.participant_name, (20 * rand + 1).to_i ] 7 workitem.fields['spotted'] << result 8 9 reply_to_engine(workitem) 10 end 11 12 def cancel(flavour) 13 14 # no need for a special implementation 15 end 16 end
Here is the 2.3.0 version. It favours “on_” methods, with implicit information (workitem, flavour, fei, …) Note that ruote 2.3.0 still accepts the above version.
1 class Scout < Ruote::Participant 2 3 def on_workitem 4 5 result = [ workitem.participant_name, (20 * rand + 1).to_i ] 6 workitem.fields['spotted'] << result 7 8 reply 9 end 10 11 # Ruote::Participant provides an empty default #on_cancel 12 end
Until now, process definitions where mostly expressed in Ruby or in XML, or directly as (JSON) abstract trees.
There is a new mini-language called Radial available in the latest ruote. It aims for terseness, looks like a mix of JSON and Python (yes, significant indentation), and is not far from what it would look like in Ruby 1.9.
1 define 2 concurrence merge_type: concat 3 scout_alice 4 scout_bob 5 scout_charly 6 leader_doug
1 Ruote.define do 2 concurrence merge_type: concat do 3 scout_alice 4 scout_bob 5 scout_charly 6 end 7 leader_doug 8 end
Radial is used as well in the “noisy” mode for debugging workflow activity, each time a workflow is launched, its radial version is displayed along with expression ids for easier activity deciphering.
The radial mini-language is parsed thanks to Parslet.
ruote-amqp needed some rework, it was too focused on queues for publishing whereas it should have been talking to exchanges. Hopefully the new version of ruote-amqp more closely follows the AMQP philosophy.
Persistence is important for a workflow engine, some processes are expected to run for long times and survive engine failures and restarts. At the heart of ruote are storage implementations.
To spare time, I decided to stop the developement of ruote-dm in favour of ruote-sequel. Ruote-sequel also benefitted from a recent rework in order to decrease the traffic between the worker(s) and the database (ruote is quite the query gun). Hopefully, as time flows and experience and feedback accumulate, workers and storage implementations get better.
It’s currently quite the vanilla storage implementation. I hope to find some time to port some of the improvements in ruote-sequel to ruote-mon to decrease traffic between the worker(s) and MongoDB.
ruote-redis slowly matured into 2.3.0. There were a few issues uncovered by various people. They are fixed by now.
Unfortunately ruote-swf, backed by Amazon SWF is still behind a corporate wall. It’s an interesting implementation, it helped mature the worker and other storage implementations. It should be available by the end of the year.
other storage implementations
ruote-couch hasn’t made it to 2.3.0. I’d like to work on it, but since I have to make sure 2.3.0 reads couches written by 2.2.0, I’m a bit hesitant. I hope to find the time for an upgrade sprint (or two), I probably want a complete rewrite.
graphical process visualization (ruote-fluo)
ruote-fluo was rendering graphically process definitions to browser canvases. It had a few issues with big processes (memory leaks).
There are a few bugs reported by Chris Conley that have to be fixed (2.3.1 hopefully).
Marco Sehrer and other have reported inconsistencies with the StorageParticipant. They have to be addressed. Maybe the solution is a rework of the storage participant or a new participant (InboxParticipant?). I’d like to see that work in 2.3.1
Many thanks for all the feedback and the contributions.
This release is dedicated to the memory of Claudio Petasecca-Donati, fellow developer, thanks for all your help.