Required result: A model that is restartable and allows the user to move between tasks 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 a process that will represents one step of our process: The step will be then used multiple times in a main process in a series of Reusable Subprocesses. We will design the omitting and skipping mechanisms in the step process.
Define the process parameters: these should provide data for the activity of the step.
For example, use the User task and design for it a form with a submit button.
The skip mechanism allows you to restart your model instances at any point without having to worry about data consistency or flow interruptions.
To implement it, we will make the flow process send data on whether the step process needs to execute its Activity to the step process. The value of the data should depend on persisted data so it remains unchanged in case of model instance restart. However, we will use a global variable to store the data to keep it simple.
Goal: Create the skipping mechanism inside step around its Task and make the flow send the omitCondition value to step.
omitCondition
parameter of type Boolean: the parameter will be sent by the parent process.omitCondition
will be true. 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
.)While here you are omitting the same task over and over again, in real world scenarios, you will omit different types of Activities:
Change the type of the User task in the step sub-process to the Executable task type and pass the user task in the activity 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: To the Task in the step process, we will attach an interrupting Catch Signal Intermediate Event. It will wait for the Task to throw a Signal: when this happens, the Signal Intermediate Event will be activated and the Task deactivated. The execution will take the outgoing flow of the event, which will enter a No Exit End Event. The end event will terminate the sub-process instance without letting the subprocess produce a token: this will prevent the parent process from continuing its execution.
To design the deactivation mechanism, do the following:
sendSignal(false, {thisModelInstance()}, "deactivate")
when clicked.{ r:Object -> true}
) so it catches any Signal.Connect the event to a No Exit End Event:
The No Exit End event ends the execution flow of the reusable sub-process just like Simple End Event. Unlike Simple End Event, it prevents the execution to continue out of the Subprocess: The Subprocess does not produce a token.
In the flow process, change the Reusable Subprocesses to Inline Event Subprocess.
Inline Event Subprocesses are considered a part of the parent process, that is, the flow process. They are instantiated as process instances while non-inline-event subprocesses create subprocess instances. Only Inline Event Subprocesses can finish with a No Exit Event.
You have implemented the following behavior:
The model can now omit already performed Activities and deactivate their step processes. Now you need to let the flow process activate the correct step when another step is deactivated. You will pass the information to the step process as a parameter in the deactivation Signal:
id
Integer parameter to step so you can identify the step to activate. The parameter will be populated by the flow process depending on the position of the Reusable Process in the flow and hold the step that should be activated upon deactivation. Still in the step process, add the Signal Start Event
Since step is an Inline Event Subprocess, all Signal Start Events in all steps will be listening for a Signal and can be activated when a Signal is received.
goto
parameter sent in the Signal: { activateStep:Integer -> activateStep == id }