Skip to content

Latest commit

 

History

History
333 lines (254 loc) · 11.9 KB

patterns__control_flow.md

File metadata and controls

333 lines (254 loc) · 11.9 KB

patterns__control_flow.md

introduction

This document describe Flor implementation for each of the Control-Flow Patterns presented by the Workflow Patterns website which catalog a comprehensive list of those workflow building blocks. Each implementation are provided with a link to the original pattern explanation and flash animation.

This is a self-evaluation. For an authoritative source, see the workflow patterns website and its mailing list.

If you disagree with a solution proposed here, you are much welcome to raise an issue pointing at why the solution doesn't match and potentially include a better solution.

index

Basic Control Flow Patterns

Advanced Branching and Synchronization Patterns

Multiple Instance Patterns

  • Multiple Instances without Synchronization
  • Multiple Instances with a Priori Design-Time Knowledge
  • Multiple Instances with a Priori Run-Time Knowledge
  • Multiple Instances without a Priori Run-Time Knowledge
  • Static Partial Join for Multiple Instances
  • Cancelling Partial Join for Multiple Instances
  • Dynamic Partial Join for Multiple Instances

State-based Patterns

  • Deferred Choice
  • Interleaved Parallel Routing
  • Milestone
  • Critical Section
  • Interleaved Routing

Cancellation Patterns

  • Cancel Task
  • Cancel Case
  • Cancel Region
  • Cancel Multiple Instance Activity
  • Complete Multiple Instance Activity

Iteration Patterns

  • Arbitrary Cycles
  • Structured Loop
  • Recursion

Termination Patterns

  • Implicit Termination
  • Explicit Termination

Trigger Patterns

  • Transient Trigger
  • Persistent Trigger

Basic Control Flow Patterns

Sequence

Chaining activities in sequence.

Use the sequence or cursor.

sequence
  task 'alpha'
  task 'bravo'

wp/explanation | wp/animation | top

Parallel Split

The concurrence is the main tool for the parallel split.

concurrence
  #
  # alpha and bravo will be tasked concurrently
  #
  task 'alpha'
  task 'bravo'

wp/explanation | wp/animation | top

Synchronization

The concurrence by waiting (by default) for all its children to reply is the simplest flor synchronization tool.

sequence
  task 'alpha'
  concurrence
    task 'bravo'
    task 'charly'
  task 'delta' # task 'delta' will be reached once 'bravo' and 'charly' both have replied

wp/explanation | wp/animation | top

Exclusive Choice

The simplest flor procedure to use to support this pattern is if.

  sequence

    # ...

    if
      f.customer.age > 21 # condition
      sequence # then
        set f.customer.type 'adult'
        order_kit _
      sequence # else
        set f.customer.type 'non-adult'
        order_teenager_kit _

    # ...

The case and match are the other two contenders for exclusive choice.

wp/explanation | wp/animation | top

Simple Merge

A simple merge occur when two (or more) exclusive branch converge. As seen in exclusive choice this pattern is implicitly supported. It simply occurs when the ‘then’ or the ‘else’ clause of an if terminates and the flow resumes.

wp/explanation | wp/animation | top

Advanced Branching and Synchronization Patterns

Multi-Choice

concurrence and if can be combined to support this workflow control pattern.

sequence
  # ...
  concurrence
    if f.traffic or f.crime
      task "despatch police"
    if f.fire
      task "despatch fire engine and ambulance"
    if f.wounded
      task "despatch ambulance"
  # ...

The concurrence may result in 0 to 3 tasks being "emitted", in case of 0, the flow will immediately resume after the concurrence. Else, the flow will wait until the 1 to 3 tasks have completed.

wp/explanation | wp/animation | top

Structured Synchronizing Merge

The explanation for this pattern sports an example stating:

Depending on the type of emergency, either or both of the despatch-police and despatch-ambulance tasks are initiated simultaneously. When all emergency vehicles arrive at the accident, the transfer-patient task commences.

Here is a naive flor translation (see previous pattern for its origin):

sequence
  # ...
  concurrence
    task "despatch police" if f.traffic or f.crime
    task "despatch ambulance" if f.wounded
  task "transfer-patient"
  # ...

The concurrence procedure, by default, waits for all its children to respond before ending and replying to its parent procedure (here a sequence. The sequence then hands the flow to the task "transfer-patient" followup.

wp/explanation | wp/animation | top

Multi-Merge

Here is the example given for this merge:

The lay_foundations, order_materials and book_labourer tasks occur in parallel as separate process branches. After each of them completes the quality_review task is run before that branch of the process finishes.

Here is a naive flor translation (tasks are expressed directly, so "lay_foundations" could refer on the tasker "lay_foundations" or the function "lay_foundations", depending on your setting:

sequence
  # ...
  concurrence
    lay_foundations _
    order_materials _
    book_labourer _
  quality_review _
  # ...

But the "the quality_review task is run before that branch (...) finishes" is not respected. This is better, but verbose:

sequence
  # ...
  concurrence
    sequence
      lay_foundations _
      quality_review _
    sequence
      order_materials _
      quality_review _
    sequence
      book_labourer _
      quality_review _
  # ...

This uses a wrapper function, it calls it with a block (like a Ruby block):

sequence

  # ...

  define with_quality_review
    yield _           # the wrapped block is called
    quality_review _  # then the review is performed

  concurrence
    with_quality_review
      lay_foundations _
    with_quality_review
      order_materials _
    with_quality_review
      book_labourer _

TODO: alternatives...

wp/explanation | wp/animation | top

Structured Discriminator

Here is the example given for this merge:

When handling a cardiac arrest, the check_breathing and check_pulse tasks run in parallel. Once the first of these has completed, the triage task is commenced. Completion of the other task is ignored and does not result in a second instance of the triage task.

sequence
  concurrence expect: 1 remaining: 'forget'
    check_breathing _
    check_pulse _
  triage _

The concurrence expects one reply and then forgets the remaining branch.

wp/explanation | wp/animation | top

Cancelling Discriminator

The example given for this merge:

After the extract-sample task has completed, parts of the sample are sent to three distinct laboratories for examination. Once the first of these laboratories completes the sample-analysis, the other two task instances are cancelled and the review-drilling task commences.

sequence
  extract_sample _
  concurrence expect: 1 remaining: 'cancel'
    examine_sample 'laboratory 1'
    examine_sample 'laboratory 2'
    examine_sample 'laboratory 3'
  drill_review _

The concurrence expects one reply and then cancels the remaining branches.

Here is a variant using c-each:

sequence

  set labs [ 'lab alpha', 'lab biometa', 'lab cruz' ]

  # ...

  extract_sample _
  c-each labs expect: 1 remaining: 'cancel'
    examine_sample lab: elt
  drill_review _

wp/explanation | wp/animation | top

Multiple Instance Patterns

State-based Patterns

Milestone

A task is only enabled when in a specific state (typically a parallel branch).

Flor's workflow definition might be paraphrased as: "E is tasked only if the execution has the tag 'bravo'":

concurrence
  sequence
    task 'A'
    task 'B' tag: 'bravo'
    task 'C'
  sequence
    task 'D'
    task 'E' if tag.bravo
    task 'F'

The predecessor to Flor (Ruote) was proposing a syntax a bit more convoluted.

wp/explanation | wp/animation | top

Cancellation Patterns

Iteration Patterns

Termination Patterns

Trigger Patterns