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:
- Create a GO-BPMN project.
- Right-click the project and select Import > Archive file.
- Enter the path to the zip file into the From archive file field.
- 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.
The pattern is as follows:
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:
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.
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:
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.
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:
omitCondition
parameter of type Boolean.omitCondition
will be true. 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:
omitCondition -> lastSuccessfulStep >= 1
(When the last successful step equals or is larger than 1, the condition is true
.)omitCondition -> lastSuccessfulStep >= 2
(When the last successful step equals or is larger than 2, the condition is true
.)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.
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:
To design the deactivation mechanism, do the following:
sendSignal(false, {thisModelInstance()}, "deactivate")
when the user clicks a "Deactivate" button.{ r:Object -> true}
).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.
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).
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:
id
Integer parameter to the step so that you can start a particular sub-process 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.{ activateStep:Integer -> activateStep == id }