LSPS documentation logo
LSPS Documentation
Agile Processes

Required result: A process will recover its progress based on data after restart and it is possible to switch from one activity to another activity arbitrarily.

Note: You can download an example implementation here. To import the model, do the following:

  1. Create a GO-BPMN project.
  2. Right-click the project and select Import > Archive file.
  3. Enter the path to the zip file into the From archive file field.
  4. Click Finish.

Patterns of agile mechanisms solve the following:

  • Set the correct execution state after restart: on restart, the process omits activities that were already performed.

    For example, if you interrupted an order-dispatch process at a moment when the order is ready to be dispatched, on restart, the process omits the invoicing and payment activities and proceeds to the dispatch activity.

    This also allows you to update the underlying model easily: you stop your model instances, upload a new version of the model, and resume the stopped model instance according to the new model. The new model instance get into the same or equivalent execution status as the original model instance on resume.

  • Skip arbitrarily through activities: skipping is used to implement such features as breadcrumb navigation; the user can switch between activities freely. On switch, the process deactivates the current activity and activates another.

The pattern is as follows:

  • Each "skippable" flow sequence is implemented as a process or a task type: the sequence has the activity reflection type enabled so it can be triggered by the Execute task.
  • The sequence is executed by an Execute task of a wrapper process, which wraps the Execute task in the skipping mechanism.
  • The wrapper process takes a parameter with the current step: if the current step does not correspond to the required step, the Execute task is not executed.
  • The wrapper process is called as a subprocess from an orchestrating main process.
  • If the skippable flow sequence signalizes that it should be deactivated, the Executable task handles the signalization, deactivates the wrapper process and activates another wrapper process.

Designing the Skeleton

We will create the main process that will run a series of Reusable Subprocesses. In our case the Reusable Subprocesses will run a simple process with a User task, instead of the Execute task so we can keep it simple.

Design the subprocess:

  1. Create a BPMN-based process that will hold the Activity. We will refer to this process as the step.

    The step holds the activity that you want to execute or omit depending on the business data, so this could be the dispatch order or payment order; the process would be more complicated in real-word scenarios.

  2. Unselect the Instantiate Automatically option in the process properties to prevent bogus instances of the step process.
  3. Define the parameters of the activity as required.

    Use a task that will stop the execution, so you can check the behavior of the process easily: for example, use the User task and design a form, for example, with a submit button.

Design the coordinating parent process:

  1. Create a BPMN-based process with a flow of Reusable Processes: set the step process as their content:

    In a new process definition, insert a None Start Event and a few Reusable Sub-Processes connected by normal flows so that one instance of the Reusable Processes is running at a time.

    You have a functional model: run it and check that the process instance has one step sub-Processes running at a time and that the step sub-process is not instantiated as its own process instance.

Model instance details of a successful run

Designing Omitting

The omitting mechanism of the step process will check if the given subprocess instance actually needs to run: we will send the subprocess the input for the condition from the parent process.

TODO: The goal is to create the skipping and omitting mechanism inside the Subprocess around an activity. The activity represents individual steps of the Process which we want to be able to skip or omit.

Let's design the omitting mechanism:

  1. In the step process, design the evaluation of the condition:
    1. Define the omitCondition parameter of type Boolean.
    2. Design the workflow that will avoid the activity and that will be used when the omitCondition will be true.
    3. Make the flow pointing to the activity the default flow.
  2. In the flow process, pass the omitCondition argument to each Reusable Process.

    We will make it depend on global Integer variable lastSuccessfulStep but in a real solution, it should depend on business data:

    • on the first Reusable Subprocess omitCondition -> lastSuccessfulStep >= 1 (When the last successful step equals or is larger than 1, the condition is true.)
    • on the second Reusable Subprocess omitCondition -> lastSuccessfulStep >= 2 (When the last successful step equals or is larger than 2, the condition is true.)
  3. Test the process, set the initial value of lastSuccessfulStep to a value (0, 1, and 2) and run a model instance with the value. Check the behavior of the subprocesses: make sure the skipping works as expected.
Run with lastSuccessfulStep set to 1. The subprocess that used the omitting flow displayed below.

Real-World Adaptations

  • In real models, you omit different types of Activities:

    Define the Activity in the step sub-process as the Executable task type and pass its activity as a parameter of the sub-process along with the condition parameter.

  • To evaluate the conditions for omitting, use business data persisted in the database. Modify these as part of each step sub-process.

Designing Deactivation

The deactivation mechanism terminates the current sub-process instance under specific circumstances. It could be either when it receives a signal or when a condition becomes true.

We will use a Signal: On the activity in the step process, an interrupting Catch Signal Intermediate Event will wait for the Activity to throw a Signal: when this happens, the Activity will be deactivated. The outgoing flows of the intermediate event will enter a No Exit End Event so they terminate the sub-process instance without letting the subprocess produce a token: we do not want the parent process to continue the flow.

To sum it up, when the Activity throws the Signal in one of the step instances:

  1. The Activity is terminated by its Catch Signal Intermediate Event;
  2. The step subprocess instance finishes.
  3. The coordinating process instance finishes since no sub-process instance is running.

To design the deactivation mechanism, do the following:

  1. Adapt the Activity in the step process so it throws a Signal when it should be deactivated; for example, if you are using a User task, edit its form so it calls sendSignal(false, {thisModelInstance()}, "deactivate") when the user clicks a "Deactivate" button.
  2. Adapt the step so when it receives a Signal it finishes:
    1. Add an interrupting Intermediate Catch Signal Event to the boundary of the Activity (set the filter to catch any signal from the activity, for example, { r:Object -> true}).
    2. Connect the event to a No Exit End Event:

      The event will consume the token of the reusable sub-process just like Simple End Event but it does not produce a token that would leave the sub-process. We can create another token on another sub-process instance.

  3. In the coordinating Process, change the Reusable Subprocesses to Inline Event Subprocess. Note that only inline event sub-processes can finish with a No Exit Event. They are executed as part of their parent: if defined in a process, they create process instances (while non-inline-event subprocesses create subprocess instances).

  4. Run the model and deactivate it in one of the steps.
    Model instance deactivated in the first subprocess. The diagram with the activity deactivated by the Catch Signal Event is below.

Designing Activation

Now we can omit already performed activities and we can deactivate them. To get all the features of agile processes we now need to create the activation mechanism that will create a step instance when a step is deactivated. This will allow us to switch from one step to another arbitrarily.

To be able to do this, we need to let the parent process know which task it needs to create: we will pass the information as a parameter to the step process:

  1. Add the id Integer parameter to the step so that you can start a particular sub-process after deactivation.
  2. Add information on which step should be activated after deactivation: sendSignal(false, {thisModelInstance()}, goto). In a form, the "goto" information could be based on user input. If you are using a User task as your activity, the Deactivate button turns into a Go To Activity button. Also consider navigating away from the to-do since you will be looking at the to-do of the deactivated task if you do not.
  3. Add the Signal Start Event: since all Signal Start Events in all steps will be listening for a Signal, define its filter to match the id parameter which is sent as part of the Signal (goto). It must match the id of the step: { activateStep:Integer -> activateStep == id }
  4. In the coordinating process, add the id parameter value to the reusable sub-processes and the goto parameter if you added the goto parameter to your subprocess.
  5. Run the model.

Real-World Adaptations

  • Typically, you will skip to a step based on input provided by a user in a to-do: in such a case, you will need to adapt the respective form so it passes the go-to data: a listener could send the signal with a goto value from an input field.