await

The ‘await’ expression is the successor of the ‘listen’ expression
(Ruote::Exp::ListenExpression). It’s been introduced in ruote 2.3.0.

Hopefully it has a simpler syntax than ‘listen’. The major difference
between listen and await is that await, by default, listens only
to events in the same process instance.

This expression blocks until an event occurs somewhere else in the same
process instance.

              concurrence do
                sequence do
                  participant 'alice'
                  await :left_tag => 'a'
                  participant 'bob'
                end
                sequence :tag => 'a' do
                  participant 'charly'
                  participant 'doug'
                end
                sequence do
                  participant 'eric'
                end
              end
            

In this example, the flow between alice and bob, will block until ‘doug’
has replied (Yes, this example could have been written using
:left_participant => ‘doug’).

modes

‘await’, like ‘listen’ works in two mode, “once” and “multiple times”.

In the ‘once’ mode, the await expression blocks the flow until the workitem
(somewhere else in the process instance) leaves the alice participant:

              sequence do
                await :left_participant => 'alice'
                participant 'eric'
              end
            

In the ‘multiple times’ mode, the await expression triggers its children
expressions each time a matching event occurs. It never replies to its
parent expression. Here, the participant ‘post_alice’ will receive a
workitem each time, somewhere else in the process

              await :left_participant => 'alice' do
                participant 'post_alice'
              end
            

Note, that, unlike “listen” in previous versions of ruote, it’s OK
to consider the children of “await” as part of an implicit sequence:

              await :left_participant => 'alice' do
                participant 'bob'
                participant 'charly'
              end
            

Bob and charly will be applied in sequence.

tag, participant or error events

Await listens to 3 types of events: tag, participant and error events.

Here is a assortment of examples:

              await :in_participant => 'alice'
              await :reached_participant => 'alice'
              await :out_participant => 'alice'
              await :left_participant => 'alice'
            
              await :participant => 'alice'
              await :participants => 'alice' # looks better with an array
            
              # implicit OR with arrays:
              #
              await :in_participant => /^al/
              await :in_participant => %w[ alice alfred ]
              await :in_participant => [ /^al/, /fred$/ ]
            
              await :in_tag => 'phase2'
              await :reached_tag => 'phase2'
              await :out_tag => 'phase2'
              await :left_tag => 'phase2'
            
              await :tags => 'phase2'
            
              await :error
              await :error => 'ArgumentError'
              await :error => 'RuntimeError, ArgumentError'
              await :error => %w[ RuntimeError ArgumentError ]
            

Basically, the attribute is composed of a left part and a right part.
The right part is one of “in”, “reached” or “out”, “left”. “in” and
“reached” are equivalent, as are “out” and “left”.

The right part is “tag” or “participant”.

“error” can be used alone.

When “tags” and “participant(s)” are used alone, they are synonymous with
“reached_tag” and “reached_participant” respectively.

absolute tags

It’s OK to specify absolute tags, like in:

              pdef = Ruote.define do
                concurrence do
                  sequence do
                    await :tag => 'a/b'
                    echo 'a/b'
                  end
                  sequence :tag => 'a' do
                    noop
                    sequence :tag => 'b' do
                      echo 'b'
                    end
                  end
                end
              end
            

:where condition

The “await” expression accepts an optional attribute which adds another
guard which is checked to determine if the trigger should occur or not.

              pdef = Ruote.process_definition do
                concurrence :wait_for => 1 do
                  await :left_participant => 'a', :where => "${task} == 'sing'" do
                    echo 'sing-a'
                  end
                  await :left_participant => 'a' do
                    echo 'any-a'
                  end
                  concurrence do
                    participant 'a', :task => 'talk'
                    participant 'a', :task => 'sing'
                  end
                end
              end
            

In this example, the message ‘sing-a’ will be echoed only once (twice for
‘any-a’).

:global => false by default

Unlike the ‘listen’ expression, ‘await’, by default, only triggers for
events in the same process instance. To react on events whatever the
process instance, :global => true (or “true”) can be used.

              await :left_tag => 'phase1', :global => true do
                participant 'supervisor', :msg => 'phase1 over'
              end
            
            

:merge => nil/ignore

In the listen expression, the default is for the event’s workitem to
get merged into the waiting workitem. With ‘await’, the default is
the event’s workitem completely overriding the awaiting workitem.

Using the :merge attribute, other behaviours are possible.

              await :left_tag => 'phase3', :merge => 'ignore'
              await :left_tag => 'phase3', :merge => 'drop'
                # the event's workitem is ignored, the awaiting workitem is used
            
              await :left_tag => 'phase3', :merge => 'override'
                # the event's workitem is used, this is the default
            
              await :left_tag => 'phase3', :merge => 'incoming'
                # a hash merge happens, the incoming (event) workitem wins
                # workitem = awaiting.merge(incoming)
            
              await :left_tag => 'phase3', :merge => 'awaiting'
                # a hash merge happens, the awaiting workitem wins
                # workitem = incoming.merge(awaiting)
            

Note: the :where guard is always about the event’s workitem (not the
workitem as it reached the ‘await’ expression).

note: the “await” attribute

(since ruote 3.2.1)

“listen” and “await” are both ruote expressions. There is also an
attribute common to all the expressions: :await.

              concurrence do
                sequence do
                  alice
                  sequence :tag => 'stage2' do
                    bob
                  end
                end
                sequence do
                  charly
                  diana :await => 'left_tag:stage2'
                  eliza
                end
                frank
              end
            

The expressions with an await attribute suspends its application until
the awaited event happens.

This await attribute, defaults to “left_tag:”, so

              diana :await => 'stage2'
                # is equivalent to
              diana :await => 'left_tag:stage2'