OpenWFEru: Workflow and Business Process Machine engine(Introduction)
Posted by Saulius Grigaitis 24/01/2008 at 22h37
Nowadays Rails applications are RESTful, so in most cases it avoids any complex workflow(except minor things like account registration). But sometimes workflow becomes important element in application, then the quick way is to use status field, which works well at simple situations. For example Invoice model has status field, which is one of ["new", "pending", "paid", "canceled"] or so. The problem here is that workflow is hardcoded in code. So invoices with status "new" appears in new invoices page, because that action use something like Invoice.find(:all, :conditions => {:status => "new"}), and the same situation is with other pages. Here workflow is hardcoded. One day business process changes and new status of invoice is added, then programmer needs to analyze the app's code, remember the workflow implementation and change a lot of code in tests and models/views/controllers... Usually this is non-effective and painful.
Other issue - business analyst or customer provides the workflow schematics, then programmers use those. Constantly schematics or implementation of that worklow is changed, but usually synchronization between schematics and implementation is lost, because people make mistakes or are too lazy :).
Is there any solution to easer control of workflow and avoid mentioned issues? Yes, serious people call it orchestration:). The main idea is to get workflow defined in some external resource, like XML file. Then even business analyst can easily change the workflow with help of IDE, which allows to edit the workflow files(for example jBPM Process Designer for JBoss jBPM). Workflow and business process machine engine OpenWFE has been ported to Ruby, so Ruby folks can use OpenWFEru. Unfortunately, I couldn't find any usable process designer for this engine, but usually it is not painful to write process definition by hand in XML or Ruby.
There are few things that one must understand before using OpenWFEru: business processes, participants and workitems(or tasks, or tokens, or other name for the same thing).Business processes are defined via trees of expressions named process definitions. Participants are those workers, which starts to do something when get workitem. Participants can be mailer, so it sends email once it gets workitem, or web service client, so it communicates with server via API once it gets workitem, or block of Ruby code, so this code will be executed once it gets workitem, or any other allowed participant. And the most important Gotcha is workitem. Workitem itself doesn't contain any task, it's only token. But one can associate variables with this workitem, so one can pass important data from one participant to other, like the ":translator" participant pass the "translation" to ":reporter" participant in the example. So workitem is created and passed to first participant once business process is initiated, this workitem is passed to next participant according to process definition once first participant completes his task. In same way workitem is passed thought entire process and participants knows when to do their job.
Here is the simple example, which is based on openwferu.rb. There is very simple workflow: sequence of three participants. First one is you, your task is to enter text in english. Once you complete it, the workitem with the "source_text" you entered will be passed to second participant - translator. Translator here is Ruby block again, which calls google translation service(thanks to rbabel). Once text is translated, it is attached to workitem, and workitem is passed to third participant - reporter. This is Ruby block again, it only prints the source text and translated text. As you see, it is very easy to change the translator. What you need to do, is only change the block of current translator, or register new participant and replace old participant's name in process definition with new one. Also, it is very easy to analyze and change workflow, you only need to be familar with XML(actually, workflow can be defined in Ruby too). And final thing is that participants are loosely coupled, the only one thing is the attached variables to workitem. So participants are like small units, which has input and output, so it's very easy to make various combinations of those units in complex sequences.
#first install gems
$ sudo gem install openwferu
$ sudo gem install rbabel
then execute this Ruby script
require 'rubygems' require 'openwfe/def' require 'openwfe/workitem' require 'openwfe/engine/engine' require 'openwfe/participants/enoparticipants' require 'rbabel' # instantiating an engine engine = OpenWFE::Engine.new # adding some participants engine.register_participant :you do |workitem| puts "=========================================" puts "Task for You" puts "Please, enter text in english" workitem.source_text = gets puts "=========================================" end engine.register_participant :translator do |workitem| puts "==============Task for translator========" puts "translating text..." workitem.translation = workitem.source_text.translate(:en, :fr) puts "translated!" puts "=========================================" end engine.register_participant :reporter do |workitem| puts "==============Task for reporter==========" puts "Text in english:\n#{workitem.source_text}\ntranslated to text in french: \n#{workitem.translation}" puts "=========================================" end # a process definition definition = '<process-definition revision="1" name="example"> <sequence> <participant ref="you"></participant> <participant ref="translator"></participant> <participant ref="reporter"></participant> </sequence> </process-definition>' # launching the process li = OpenWFE::LaunchItem.new(definition) li.initial_comment = "please give your impressions about http://ruby-lang.org" fei = engine.launch li # 'fei' means FlowExpressionId, the fei returned here is the # identifier for the root expression of the newly launched process puts "started process '#{fei.workflow_instance_id}'" engine.wait_for fei
Yes, this example is very simple, but that was my way to show you this concept. If you understand the advantage of workflow and business process engine, then you can imagine how easy it is to implement complex workflow in dynamic enterprise, which is usually very painful without such engine.

