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.

4 comments | no trackbacks

Comments

  1. Renaud said 16/05/2008 at 10h14 later:

    Very interesting,
    very concise,
    very clear.

    It give a whole bunch of ideas
    how to implement this workflow’s concept.

    Have you already study any rule engine ?

  2. Saulius Grigaitis said 24/05/2008 at 20h09 later:

    Thanks for interest. Unfortunately, I haven’t. Seems that there are tools for that in Ruby too http://rools.rubyforge.org/. I’ll check when I have a moment.

  3. Mindaugas Kurlavicius said 27/06/2008 at 13h23 later:

    “Is there any solution to easer control of workflow and avoid mentioned issues?”

    Yes, there is and it can be made through a programming language feature called “continuations”. It is a pity that only few languages (the weird ones like “Smalltalk”, “Lisp”, “Scheme”) support that thing and although “Ruby” has continuations (in Ruby 1.9 Matz decided to remove it) it is almost impossible to use them in Rails: http://gilesbowkett.blogspot.com/2008/03/failed-attempts-at-adding-continuations.html. Of course some stupid “enterprisy” XML maybe is better way to handle state/workflow than using plain session or directly model components but web application frameworks that support continuations (Seaside, Weblocks) is an ideal way to implement some business process that requires a LOT of state/workflow management.

  4. John said 15/07/2008 at 14h01 later:

    Mindaugas,

    don’t mix “screen flow” with “business process”.

    There are applications/systems that span more that 1 web application and that manage the state of more than 1 resource.

    Best regards,

    John

Trackbacks

Use the following link to trackback from your own site:
http://www.rubyonrails.lt/trackbacks?article_id=24

(leave url/email »)

reCaptcha

   Comment Markup Help Preview comment