OpenWFEru expressions

A few paragraphs and examples about each of the expressions found in OpenWFEru.

For each expression, a link is provided to its “rdoc”, which might be pretty “empty”.

Usage examples are given in XML and / or as Ruby process definitions.

Expression names in Ruby process definitions are often preceded with an ’_’ (underscore) to help differentiate them from actual Ruby keywords and identifiers.

It’s also worth to have a look at how OpenWFEru implements each of the workflow control patterns.

 

Expressions are enumerated in the alphabetical order, but here is some kind of ‘importance order’ :


a

‘a’ is a shortcut for the attribute expression.

attribute

Makes for ugly process definitions, but anyway… With this expression, a complex value (like a list or a map) can be described directly in XML or YAML in the process definition.

rdoc for more information

cancel-process

Among the first expressions in the alphabetical order… When the workflow engine encounters this expression, it cancels completely the process instance to which it belongs.

    <sequence>
        <participant ref="before" />
        <cancel-process />
        <participant ref="after" />
    </sequence>

It this example, the participant named “after” is never reached.

Most of the time, “cancel-process” is used as a consequence to an “if” expression or uses its own ‘if’ attribute, like in :

    require 'openwfe/def'

    class TestDefinition1 < OpenWFE::ProcessDefinition
        sequence do
            participant "customer"
            _cancel_process :if => "${f:no_thanks} == true"
            concurrence do
                participant "accounting"
                participant "logistics"
            end
        end
    end

If the participant “customer” set the field “no_thanks” to “true”, the flow will never resume to the concurrence.

rdoc

case

The ‘case’ expression is an extended ‘if’. It accepts a list of children and expects the first one to be a condition to evaluate. If this child evaluates to true it will evaluate the second child as a consequence and then exit.

If the first child evaluates to false, it will jump to the third child. If there is none, it will exit, if there is one, it will evaluate it (and if it’s a condition…) (this is boring to explain).

    require 'openwfe/def'

    class DefinitionWithCase < OpenWFE::ProcessDefinition
        case do
            equals :field => "customer", :val => "El Wasabi"
            participant :ref => "salesman_1"
            equals :field => "customer", :val => "Rio Coffee"
            participant :ref => "salesman_2"
            participant :ref => "salesman_3"
        end
            #
            # attributing customers to salesmen.
            # salesman number 3 handles anything that is not 'El Wasabi' or
            # 'Rio Coffee'
    end

rdoc

concurrence

Divides the process flow into two or more concurrent lanes.

    <process-definition name="exp_mydef" revision="0.1">
        <concurrence>
            <participant ref="alice" />
            <participant ref="bob" />
            <sequence>
                <participant ref="charlie" />
                <participant ref="doug" />
            </sequence>
        </concurrence>
    </process-definition>

With OpenWFEru you could also write :

    require 'openwfe/def'

    class MyProcessDefinition01 < OpenWFE::ProcessDefinition
        _concurrence do
            _participant :ref => "alice"
            _participant "bob"
            _sequence do
                charlie
                doug
            end
        end
    end

Note that in this example, three different ways of ‘invoking’ a participant have been displayed. When used alone, participant names have not been preceded by an underscore.

rdoc (for an explanation on the merge attributes of the concurrence expression)

concurrent-iterator

This is a cross between a concurrence and an iterator.

It understands the same attributes and behaves as should be : as an iterator spawning parallel copies of its child.

An explanation with some examples

See it in action in the workflow pattern 13, 14 and 15.

Some snippets, in XML :

    <concurrent-iterator on-value="sales, logistics, lob2" to-field="p">
        <participant field-ref="p" />
    </concurrent-iterator>

In Ruby :

    sequence do
      set :field => f, :value => %w{ Alan, Bob, Clarence }
      #... 
      concurrent_iterator :on_field => "f", :to_field => "p" do
        participant "${p}"
      end
    end

rdoc

cron

A ‘cron’ expression will trigger its child expression (a new copy each time) at a determined frequency.

(Note : the ‘cron’ expression found in OpenWFEru 0.9.18 has a very different behaviour from previous versions)

This frequency can be either specified with a classical cron tab string (see man 5 crontab) or with an ‘every’ frequency, something like “every 2 hours” or “every 5 minutes and 2 seconds”.

    <!--
        trigger the subprocess 'send-reminder' once per hour from nine to
        five, from Monday to Friday.
    -->
    <cron tab="0 9-17 * * mon-fri">
        <send-reminder />
    </cron>
    #
    # trigger the subprocess named 'send_reminder' every ten seconds.
    #
    cron :every => "10s"
        send_reminder
    end

The ‘cron’ expression never replies to its parent expression, thus, used a process whose body is simply a cron expression will never terminate (unless cancelled).

The classical usage scenario involves wrapping the cron in a concurrence not expecting its reply.

    concurrence :count => 1 do
        participant :toto
        cron :every => "10m" do
            subprocess :ref => "send_reminder" :target => "toto@headlost.org.uk"
        end
    end

where the subprocess “send_reminder” is triggered every 10 minutes until participant toto is done with his activity. Note that the ‘concurrence’ is set to wait for only 1 reply (it will then cancel the branch that didn’t reply, hence cancel the cron expression, which will get descheduled).

rdoc

cursor

The ‘cursor’ expression is a sequence with extended capabilities.

It understands the following commands :

Cursor commands accept condition attributes like in :

    <cursor>
        <participant field-ref="reference_1"
        <participant field-ref="reference_2"

        <break if="${field:do_not_hire} == true" />
            <!-- do not hire if one of the references set the field
                 'do_not_hire' to true -->

        <participant ref="faculty" />
        <participant ref="hr_department" />
    </cursor>

More documentation of those conditions in the cursor command rdoc

The loop expression is a cursor that loops (you have to explicitely break or cancel it, to exit it).

cursor rdoc cursor command rdoc

The ‘cursor’ expression is used for example in the workflow control pattern 10 :Arbitrary Cycles.

pattern

defined

    <if>
        <defined field="customer">
        <!-- then -->
        <subprocess ref="call_customer" />
    </if>

Note that since OpenWFEru 0.9.17, it’s possible to write :

    _if :test => "${field:customer} is set" do
        sequence do
            participant "A"
            participant "B"
        end
    end

rdoc

equals

The ‘equals’ expression is mainly used nested within an if expression. It’s used to compare two values. A value may be a plain string, a variable or a workitem field (attribute).

Read more in the rdoc link that follows.

rdoc

eval

rdoc

exp

The ‘exp’ expression allows to choose at apply time, which expression (or participant or subprocess) to use :


    sequence do

        my_activity :variant => "sequence"
            # 
            # B works after A

        my_activity :variant => "concurrence"
            # 
            # A and B work in parallel
    end

    process_definition :name => "my_activity" do

        exp :name => "${variant}", :default => "sequence" do

            participant "A"
            participant "B"
        end
    end

The ‘name’ (and the ‘default’) attribute(s) can refer to an expression, a subprocess name or a participant name, indifferently. See the following rdoc link for a more detailed example.

rdoc

f

Is a shortcut for “field”.

field

rdoc

filter

The participant expression has a ‘filter’ attribute for filtering in and out the payload of a workitem.

There is a also a ‘filter’ expression for filtering data in and out of process segments.

    class MyProcessDefinition001 < ProcessDefinition
        sequence do

            set :field => "readable", :value => "bible"
            set :field => "writable", :value => "sand"
            set :field => "randw", :value => "notebook"
            set :field => "hidden", :value => "playboy"

            alice

            filter :name => "filter0" do
                sequence
                    bob
                    charly
                end
            end
        end

        filter_definition :name => "filter0" do
            field :regex => "readable", :permissions => "r"
            field :regex => "writable", :permissions => "w"
            field :regex => "randw", :permissions => "rw"
            field :regex => "hidden", :permissions => ""
        end
    end

In that example, participant ‘alice’ will see and be able to modify all the fields of the workitem, whereas, participants ‘bob’ and ‘charly’ will be restricted to read the fields ‘readable’ and ‘randw’ and to write to the fields ‘sand’ and ‘randw’.

rdoc

filter-definition

There is already an example of a filter definition in the description of the filter expression.

A filter definition builds and then binds a filter to an OpenWFE variable. A filter may thus be bound locally (no prefix), at the process level (”/” prefix) or at the engine level (”//” prefix).

Filter definition takes place within a process definition. They may be set directly in the process body or outside of it (still within the process definition).

    filter_definition :name => "filter0" do
        field :regex => "readable", :permissions => "r"
        field :regex => "writable", :permissions => "w"
        field :regex => "randw", :permissions => "rw"
        field :regex => "hidden", :permissions => ""
    end

rdoc

forget

The ‘forget’ expression is used to set up dead ends.

It triggers its child expression and then immediately replies to its own parent expression, not caring about any potential reply from the child.

    sequence do
        participant :a
        forget do
            sequence do
                participant :a0
                participant :a1
            end
        end
        participant :b
    end

rdoc

if

See the exclusive choice workflow control pattern.

rdoc

iterator

Given a list and a child expression (one unique child is expected), ‘iterator’ will execute the child expression once per element in the list.

    <iterator 
        on-value="alice, bob, charly"
        to-variable="next_participant"
    >
        <participant ref="${next_participant}" />
    </iterator>

is thus equivalent to

    <sequence>
        <participant ref="alice" />
        <participant ref="bob" />
        <participant ref="charly" />
    </sequence>

Of course, the list could be a bit more dynamic :

    iterator :on_value => "${f:participant_list}", :to_variable => "p" do
        participant "${p}"
    end

and since OpenWFEru 0.9.13, ‘iterator’ understands the same commands as ‘cursor’ (break/cancel, rewind/continue, skip, jump) :

    iterator :on_value => "${f:participant_list}", :to_variable => "p" do
        sequence do
            participant "${p}"
            _break :if => "${f:participant_reply} == cancel_meeting"
                #
                # if one participant wishes to cancel the meeting, no need
                # to notify the others
        end
    end

iterator rdoc cursor command rdoc

listen

This expression is used to ‘listen’ on participant events (apply or reply, by default, at apply time) and triggers a piece of process.

    <concurrence>

        <listen to="alpha">
            <subprocess ref="send-email-notification" />
        </listen>

        <sequence>
            <participant ref="alpha" />
            <participant ref="bravo" />
            <participant ref="alpha" />
        </sequence>

    </concurrence>

Each time a workitem will be dispatched to participant “alpha” (applied), a copy of the workitem will be used to run an instance of the subprocess named “send-memail-notification”.

    listen :to => "^customer_.*", :upon => "reply", :where => "${f:customer_name} == Acme" do
        concurrence do
            participant :ref => "operational_sales"
            participant :ref => "strategic_sales"
        end
    end

Makes sure that when the next workitem coming back from any participant whose name begins with “customer_” and where the field customer_name is set to “Acme”, a copy of this workitem is used to trigger a small concurrence between two sales units.

The ‘listen’ expression is not limited to its own process instance, it listens to any participant event in the engine.

Since OpenWFEru 0.9.16, listen expressions without children are possible, then simply block, waiting for a ‘message’ and when it comes in, they let their process instance resume.

    sequence do
        listen :to => "^customer_.*", :upon => "reply"
        subprocess :ref => "order_items"
    end

Listen expressions without children only work ‘once’.

OpenWFEru 0.9.16 introduces as well the ‘intercept’ and ‘receive’ aliases for the ‘listen’ expression. The concept behind this expression being “listen to”, an ‘on’ attribute as been introduced has a alias to ‘to’, think “receive on” or “intercept on”.

    receive :on => "^customer_.*"

0.9.16 also introduces a “merge” attribute, the default value is ‘false’. When set to true, the workitem used to trigger the listen expression’s nested child will be a merge of the original workitem (the one that activated the listen expression) and the incoming (the listened for) workitem.

    listen :to => "^customer_.*", :merge => true

rdoc for more information

log

Logs a message to the application log (if not specified otherwise logs/openwferu.log).

rdoc

loop

See cursor.

rdoc

lose

Loses a process segment. The ‘lose’ expression applies its child expression, but it never replies to its parent expression.

May be useful in concurrence cases where a certain number of answers are expected.

    <concurrence count="1">
        <!-- this concurrence expects two answers -->

        <lose>
            <!-- will be applied, but 'lose' will never reply 
                 to the concurrence -->
            <participant ref="alice" />
        </lose>

        <participant ref="bob" />
        <participant ref="charly" />
            <!-- the concurrence will be over as soon as bob or charly
                 will have replied -->

    </concurrence>

rdoc

parameter

‘parameter’ is not a real flow expression. It is used to state and check which required workitem/launchitem fields at present and valid at launch time.

<process-definition name="exp_x" revision="0">

    <!-- required workitem fields -->

    <parameter field="customer" />
    <parameter field="address" default="" />
    <parameter field="zip" type="integer" />
    <parameter field="town" />
    <parameter field="phone" match="^[0-9]{3}-[0-9]{7}$" />
    <parameter field="customer_type" default="2" type="int"/>

    <!-- the body of the process definition -->

    <sequence>
        <participant ref="service0" />
        <participant ref="service1" />
        <play-the-music/>
    </sequence>

    <!-- subprocesses -->

    <process-definition name="exp_play-the-music">
        <participant ref="musician" />
    </process-definition>

</process-definition>

parameters (‘param’ is valid as well) have to be located outside of the body of the process definition (as a direct child of the ‘process-definition’ tag).

In that example, the process launch will immediately fail (even if the launch is asynchronous), if the launchitem doesn’t contain the fields (attributes) ‘customer’, ‘zip’, ‘town’ and ‘phone’. If the field ‘zip’ is set to something that can be converted to an integer, the launch will fail. If the ‘phone’ field value doesn’t match the given regular expression, the launch will fail. If the field ‘address’ is missing, it will be replaced by an empty string (the default value for that field). If the field ‘customer_type’ is not explicitely given, its value will be the integer ‘2’.

In a ruby process definition, it looks like :

    require 'openwfe/def'

    class MyProcessDefinition_01 < OpenWFE::ProcessDefinition

        #
        # required fields in the launchitem

        param :field => "customer"
        param :field => "address", default => ""
        param :field => "zip", type => "integer"
        param :field => "town"
        param :field => "phone", match => "^[0-9]{3}-[0-9]{7}$"
        param :field => "customer_type", default => 2, type => :int

        #
        # process definition body

        sequence do
            service0
            service1
            play_the_music
        end

        #
        # subprocesses

        process_definition :name => "play_the_music"
            musician
        end
    end

participant

This expression is one of the most important in OpenWFE (it’s featured in most of the process definition examples of this page).

A participant is usually located outside of the engine and waits for workitem to be delivered by the engine.

Participants are registered in the participant-map of the engine.

Multiple process definitions may share the same participants (processes != organizational chart).

A classic participant may be a workitem store, queried by a web application for human participants in business processes.

participant implementations shipping with OpenWFEru

rdoc for more information

process-definition

Usually the “process_definition” name is used for this expression, but “define” and “workflow_definition” are usable as well.

    process_definition :name => "my_process", :revision => "y"
        sequence do
            participant "alpha"
            participant "bravo"
        end
    end

The same definition, in XML :

    <process-definition name="my_process" revision="y">
        <sequence>
            <participant ref="alpha" />
            <participant ref="bravo" />
        </sequence>
    </process-definition>

In a Ruby process definition, this is also OK :

    class MyDef0 < OpenWFE::ProcessDefinition
        sequence do
            sub0
            sub1
        end

        process_definition :name => "sub0" do
            participant "cold"
        end
        
        definition "sub1" do
            #
            # ':name => ' not used

            participant "not cold"
        end
    end

rdoc

print

(only used for testing and debugging purposes)

rdoc

q

Is a shortcut for “quote”.

quote

rdoc

redo

Every expression accepts an implicit ‘tag’ attribute which defines a name under which a copy of the expression before evaluation is kept along with the workitem as applied (as received by the expression tagged).

The name (the tag) can then be used by a ‘redo’ or an ‘undo’ expression.

    sequence do
        sequence :tag => "core_job" do
            participant "alice"
            participant "bob"
        end
        participant "charly"
        _if :test => "${f:charly_not_happy} == true" do
            _redo :ref => "core_job"
        end
    end

Maybe this example should be ‘implemented’ with a

rdoc

related : using tags for signalling ‘process state’

reserve

This expression ensures that segments of a process instance are not run simultaneously.

It uses a mutex variable. A variable bound at engine level (prefixed with ”//”) can be used to prevent segments of totally different processes to execute simultaneously.

   concurrence do
       sequence do
           activity_a
           reserve :mutex => :m do
               activity_b
           end
           activity_c
       end
       sequence do
           activity_d
           reserve :mutex => :m do
               sequence do
                   activity_e
                   activity_f
               end
           end
       end
   end

In this example, the while the activity_b is performed, the sequence of activities e and f cannot be performed.

Note that for short, a symbol :m was used instead of the string “m”. OpenWFEru turns the symbol into the corresponding string.

<!-- process A -->

    <process_definition name="A" revision="0.0">
        <sequence>
           <participant ref="alice" />
           <reserve mutex="//guard0">
               <participant ref="alfred" />
           </reserve>
        </sequence>
    </process_definition>

<!-- process B -->

    <process_definition name="B" revision="0.0">
        <sequence>
           <participant ref="bob" />
           <reserve mutex="//guard0">
               <participant ref="berthe" />
           </reserve>
        </sequence>
    </process_definition>

In this XML example, the engine will prevent ‘alfred’ and ‘berthe’ from performing their task simultaneously, in processes A and B respectively. This is achieved by registering the mutex at the engine level (prefix ”//”).

rdoc

See the interleaved parallel routing workflow control pattern

restore

Restores the payload of a workitem previously saved in a variable or copies the value of a [sub] field as the top value of the workitem payload.

There are many options for this expression. Check the rdoc for a detailed explanation.

Since OpenWFEru 0.9.17, ‘restore’ has a ‘set-fields’ alias. It can be quite convenient for setting the payload of a workitem at the beginning of a business process.

class Registration < OpenWFE::ProcessDefinition
    set_fields :value => {
        "name" => "",
        "address" => "",
        "email" => ""
    }
    sequence do
        approve_registration
        perform_registration :if => "${approved} == true"
        notify_customer
    end
end

(The usual technique for pre-filling a workitem is by providing a launchitem when launching the business process

    li = OpenWFE::LaunchItem.new "http://process.server.com/definitions/xyz.xml"
    li.customer = { "name" => "Toto", "age" => 34 }
    li.request_type = "credit"

    openwferu_engine.launch li

)

rdoc

reval

This expression evals the Ruby code nested within it.

    <sequence>
        <reval>$i = 0</reval>
        <loop>
            <participant ref="toto" />
            <reval>$i = $i + 1</reval>
            <break if="${r:$i == 10}" />
            <!-- a variant :
            <break rif="$i == 10" />
            -->
        </loop>
    </sequence>

Within a ‘reval’ piece of code, the two principal hooks within the engine ‘bowels’ are self which points to the RawExpression instance itself and workitem

    class Reval4 < OpenWFE::ProcessDefinition
        sequence do
            reval """
                engine = self.application_context['__tracer']

                workitem.currently_active_processes =
                    engine.list_processes.join('\n')

                'done' # will be placed in the workitem field '__result__'
            """
            participant :toto
        end
    end

The result of ‘reval’ is placed in the field named

__result__
as a String.

The code is evaluated at a SAFE level of 3 (see http://www.rubycentral.com/book/taint.html for more information about those levels).

You have to explicitely set the :ruby_eval_allowed param to true in the application context of the engine else the ‘reval’ expression will raise an exception.

    engine.application_context[:ruby_eval_allowed] = true

rdoc

save

Saves a workitem to a variable or save the attributes of a workitem in a field (of that same workitem).

Is used in conjunction with restore.

rdoc

sequence

Simply chaining other flow expressions.

    <process-definition name="exp_my_definition" revision="0">
        <sequence>
            <participant ref="alpha" />
            <participant ref="bravo" />
            <participant ref="charly" />
        </sequence>
    </process-definition>

In Ruby :

    require 'openwfe/def'

    class MyDefinition0 < OpenWFE::ProcessDefinition
        sequence do
            participant "alpha"
            participant "bravo"
            participant "charly"
        end
    end

pattern rdoc

set

Is used to set the value of a variable or the value of a workitem field (attribute).

It may placed outside of the body of a process definition, it will be evaluated before the body gets applied (executed).

    require 'openwfe/def'

    class MyDefinition0 < OpenWFE::ProcessDefinition
        sequence do
            participant "alpha"
        end

        set :field => "city", :value => "Kyoto"
        set :field => "country", :value => "Japan"
    end

The participant ‘alpha’ will recevive a workitem with fields ‘city’ and ‘country’ set to ‘Kyoto’ and ‘Japan’ respectively. This technique is useful for keeping long settings out of the process ‘logic’ itself.

The unset cannot be placed outside of a process body. Filter definitions can.

Shorter version of the attributes are OK :

    require 'openwfe/def'

    class MyDefinition0 < OpenWFE::ProcessDefinition
        sequence do
            set :f => "customer_name", :val => "(fill this field)"
            participant "alpha"
        end
    end

The ‘set’ expression accepts an ‘escape’ attribute to prevent dollar substituation from occurring.

    set :v => "v0", :val => "my ${template} thing", escape => true

rdoc

set-fields

“set-fields” is an alias for restore.

rdoc

sleep

Makes a process segment sleep for a while.

    <sequence>

        <sleep for="3d" />
            <!-- sleeping for 3 days -->

        <sleep until="Mon Dec 03 10:48:03 +0900 2007" />

    </sequence>
    sequence do

        sleep :for => "3m10s"
            # sleeping for 3 minutes and 10 seconds

        sleep :until => "Mon Dec 03 10:48:03 +0900 2007"
            # sleeping until some point in time

        sleep "3M10d"
            # sleeping for 3 months and 10 days
    end

rdoc

subprocess

This expression is used to trigger a subprocess.

    <process-definition name="chores" revision="0">

        <sequence>
            <subprocess ref="take_out_garbage" />
            <subprocess ref="do_the_laundry" type="white" />
            <subprocess ref="do_the_laundry" type="colors" />
        </sequence>

        <process-definition name="take_out_garbage">
            <concurrence>
                <participant ref="al" activity="take out old paper" />
                <participant ref="bob" activity="take out garbage" />
            </concurrence>
        </process-definition>

        <process-definition name="do_the_laundry">
            <sequence>
                <participant ref="al" activity="sort ${type}" />
                <participant ref="bob" activity="clean ${type}" />
                <sleep for="1h30m" />
                <participant ref="al" activity="hang ${type}" />
                <participant ref="al" activity="iron ${type}" />
            </sequence>
        </process-definition>
    </process-definition>

Note how the variable ‘type’ was set to ‘white’ and then ‘colors’ and used within the “do_the_laundry” subprocess.

    class Chores0 < OpenWFE::ProcessDefinition

        sequence do
            subprocess :ref => "take_out_garbage"
            do_the_laundry :type => "white"
            subprocess :ref => "do_the_laundry", :type => "colors"
        end

        process_definition :name => "take_out_garbage" do
            concurrence do
                participant :ref => "al", :activity => "take out old paper"
                bob :activity => "take out garbage"
            end
        end

        process_definition :name => "do_the_laundry" do
            sequence do
                participant :ref => "al", :activity => "sort ${type}"
                participant :ref => "bob", :activity => "clean ${type}"
                sleep :for => "1h30m"
                al :activity => "hang ${type}"
                al :activity => "iron ${type}"
            end
        end
    end

Note how the subprocess name (and the participant names) can be used as expression names for a shorter syntax. Of course names with white spaces and other niceties won’t work for this shorter syntax.

If the engine :remote_definition_allowed parameter has been set to true, it’s OK to reference process definitions via their URL :

    sequence do
        participant "al"
        subprocess :ref => "http://company.process.server/defs/defXYZ.xml"
    end

rdoc

timeout

A generic timeout mechanism : sets a timeout for a whole process segment, not just a single participant or when expression.

    <timeout after="1w">
        <concurrence>
            <participant ref="alpha" />
            <subprocess ref="do_the_homework" />
        </concurrence>
    </timeout>
    _timeout :after => "2d" do
        sequence do

            participant :ref => "alpha", :timeout => "1d"
                # of course individal timeout settings are still ok

            participant :ref => "bravo"
        end
    end

Note that when using a Ruby process definition, you’d better escape the ‘timeout’ expression with an underscore at the front to avoid collisions with the ‘timeout’ method provided by the timeout.rb standard Ruby library.

rdoc

undefined

    <if>
        <undefined field="customer">
        <!-- then -->
        <subprocess ref="determine_customer" />
    </if>

Note that since OpenWFEru 0.9.17, it’s possible to write :

    _if :test => "${field:customer} is not set" do
        sequence do
            participant "A"
            participant "B"
        end
    end

rdoc

undo

Every expression accepts an implicit ‘tag’ attribute which defines a name under which a copy of the expression before evaluation is kept along with the workitem as applied (as received by the expression tagged).

The name (the tag) can then be used by a ‘redo’ or an ‘undo’ expression.

    concurrence do
        sequence :tag => "side_job" do
            participant "alice"
            participant "bob"
        end
        sequence do
            participant "charly"
            _undo :ref => "side_job"
        end
    end

In this example, after participant ‘charly’ did his job, the first sequence (tagged ‘side_job’) will get cancelled (and its reply to the parent ‘concurrence’ will get triggered).

See also the redo expression.

rdoc

related : using tags for signalling ‘process state’

unset

rdoc

v

Is a shortcut for “variable”.

variable

rdoc

when

The ‘when’ expression polls a conditional statement and triggers the nested process segment when the condition evaluates to true.

    <concurrence>
        <participant ref="alpha" />
        <when test="${for_bravo} == true">
            <participant ref="bravo" />
        </when>
        <participant ref="charly" />
    </concurrence>

When the variable “for_bravo” will contain the value “true”, participant “bravo” will receive a workitem.

By default ‘when’ evaluates the condition until true every 10 seconds.

    concurrence do
        alpha
        when :test => "${for_bravo} == true", :frequency => "1h", :timeout => "13d4h" do
            bravo
        end
        charly
    end

In this Ruby process definition (where all the participant expressions where simplified to just their names), the when condition is checked only every hour and after thirteen days and four hours, the ‘when’ is cancelled (and participant bravo will not receive a workitem).

Note that in both examples, the concurrence will wait until the when expression resumes the process.

rdoc

wait

This expression is very similar to when, but it doesn’t accept a nested expression. It blocks until its ‘until’ condition evaluates to true or until it times out.

May make some process definitions more readable.

rdoc for more information