Class Ruote::Exp::AwaitExpression
In: lib/ruote/exp/fe_await.rb
Parent: FlowExpression

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'

Methods

Constants

INS = %w[ in entered reached ]
OUTS = %w[ out left ]
SPLIT_R = /^(?:(#{(INS + OUTS).join('|')})_)?(tag|participant|error)s?$/
AAWAIT_R = /^(?:(#{(INS + OUTS).join('|')})_)?(tag|participant)s?\s*:\s*(.+)$/   attribute wait regex
KLASS_R = /^(::)?([A-Z][a-z]+)+(::([A-Z][a-z]+)+)*$/   matches Ruby class names, like "Ruote::ForcedError" or "::ArgumentError"

Protected Class methods

Made into a class method, so that the :await common attribute can use it when parsing :await…

Public Instance methods

Protected Instance methods

Overriding the parent‘s reply_to_parent to make sure the tracker is removed before (expression terminating, no need for it to track anything anymore).

[Validate]