Camunda process engine plugin to simulate process execution.
When execution process definitions, the process engine waits from time to time for external events, for example user actions, conditions, timeouts etc. This process engine plugin will generate these events to run processes without external interaction, hence, to simulate real world scenarios.
They way if and when these events are triggered and if and what payload data is to be generated is configured by Camunda Properties in the bpmn-files. Optionally, all these properties can be set externally, for example in property files.
The plugin is able to simulate the past...
Have a look at the example project, it is intended to be self explanatory.
simNextFire
:<expression giving date>
simInitBusinessKey
:<expression giving string>
simInitPayload
:<varname>=<expression giving arbitrary value>
simNextFire
:<expression giving date>
Note for signals: The signal is not delivered globally but only to the execution that waits at the receive event.
simNextComplete
:<expression giving date>
simNextClaim
:<expression giving date>
simClaimUser
:<expression giving string>
Note: Please make sure that you specify a Claim User if you specify next claim time (simNextClaim and simClaimUser always together).
TODO: Also simulate multi claim, candidates...
Replace behaviour by no-op, except following is set:
simCallRealImplementation
:true
simNextFire
:<expression giving date>
Replace behaviour by no-op, except DMN, this is "normally" called.
Always stripped away, except the following is set:
simKeepListeners
:true
simGeneratePayload
:<varname>=<expression giving arbitrary value>
You have to
- load the simulator engine plugin
- (if needed) add your own payload generator
In the example project, this is done in spring-boot by simply registering two beans. One holds the plugin itself (and the Camunda spring-boot-starter does some magic to load it on engine bootstrap). The second is the payload generator shipped with the plugin. Here, you can give your own payload generator bean, for example by inheriting from the shipped one and adding domain based functionality (if it is not domain specific -- please contribute your work to this plugin).
For other containers of the Camunda engine like tomcat, wildfly etc., especially those without DI, you can set your custom payload generator as follows:
public class MyProject {
static {
SimulatorPlugin.setPayloadGenerator(new MyShinyPayloadGenerator());
}
}
It is in a static block since you have to make sure it is executed as soon as possible, in particular before any BPMN file is parsed by the engine.
The so provided payload generator can be accessed in expressions with the name g
.
By default, the shipped payload generator is used, so it is always possible to use expressions in properties like simGeneratePayload: name=${g.firstname()}
, even if you are in a non-DI setup.
-
Add the simulator dependency to your pom file. There is an entry in Maven Central for the BPM simulator. Be sure to check for newer versions.
<dependency> <groupId>com.camunda.consulting</groupId> <artifactId>camunda-bpm-simulator</artifactId> <version>1.6.0</version> </dependency>
-
Add the follow line of code to your Camunda Application class. You can experiment with time frames: SimulationExecutor.execute(DateTime.now().minusMonths(1).toDate(), DateTime.now().toDate());
public static void main(String... args) { SpringApplication.run(CamundaApplication.class, args); SimulationExecutor.execute(DateTime.now().minusMonths(1).toDate(), DateTime.now().toDate()); }
-
Add the following bean to your Camunda Application class:
@Bean public SimulatorPlugin simulatorPlugin() { return new SimulatorPlugin(); }
-
Be sure the following imports have been added to the Camunda Application class:
import com.camunda.consulting.simulator.SimulationExecutor; import com.camunda.consulting.simulator.SimulatorPlugin;
-
Next, add extensions to various nodes in your process. You'll need extensions on start nodes, human tasks, and some service tasks. In the Extensions tab add a property called simNextFire with a value of ${g.timesPerDay("a_unique_name","start_time_in_24_hour_format","end_time_in_24_hour_format", number_of_times_you_want_to_fire_in_that_duration)}. See below. The 'g' object is understood by the plugin to be the simulator generator object. Note: For a wider range of starts per day you may want to replace the static number in the example below (88) with a function like g.uniformLong(0, 200)
-
Add simNextFire extensions to human tasks. Service tasks, business rules tasks, send tasks, and script tasks run as no ops during simulation. A sample value for a human could be ${g.nowPlusMinutes(g.uniformInt(minimum_minute_duration, maximum_minute duration))}. This will produce a uniform distribution of duration values from the minimum to the maximum. You can also use milliseconds, seconds, hours, days, weeks, months, or years.
-
You can add a wide range of data to the process using simGeneratePayload property. In this example we'd like the simulator to select between three values - "yes", "no", or "maybe". It then assigns the value to the "approved" variable which is needed for the gateway to work.
-
If you want to unevenly distribute values you can use a Normal or Beta distribution by using the normalFromArgsX or betaFromArgsX functions. Supply the values to be selected (from two up to nine) and then supply the mean and standard deviation (typically decimals from 0 to 1) for the normal distribution function. For a beta distribution supply the alpha and beta typically integers. See below for examples.
-
Now when you start the application the simulator will generate process instance and task instance data to make Cockpit and Optimize reports more interesting to view without having to run process instances manually. Be sure to have a look at the PayloadGenerator and SimulationExecutor classes for additional methods to use.
- think about throwing BPMN errors
- think about keeping execution/task listeners/
Manually trigger a release workflow run with the desired parameters for current and next version.