Multiple Instance

A multi-instance activity is a way of defining repetition for a certain step in a business process. In programming concepts, a multi-instance matches the construct: it allows execution of a certain step or even a complete subprocess for each item in a given collection, sequentially or in parallel.

A multi-instance is a regular activity that has extra properties defined (so-called multi-instance characteristics) which will cause the activity to be executed multiple times at runtime. Following activities can become multi-instance activities:

  • Service Task
  • Send Task
  • User Task
  • Business Rule Task
  • Script Task
  • Receive Task
  • Manual Task
  • Call Activity
  • Transaction Subprocess
    A Gateway or Event can not become multi-instance.

If an activity is multi-instance, this is indicated by three short lines at the bottom of the activity. Three vertical lines indicate that the instances will be executed in parallel, while three horizontal lines indicate sequential execution.

As required by the specification, each parent execution of the created executions for each instance will have the following variables:

  • nrOfInstances: the total number of instances
  • nrOfActiveInstances: the number of currently active, i.e., not yet finished, instances. For a sequential multi-instance, this will always be 1
  • nrOfCompletedInstances: the number of already completed instances
    These values can be retrieved by calling the execution.getVariable(x) method.

Additionally, each of the created executions will have an execution-local variable (i.e., not visible for the other executions and not stored on process instance level) :

  • loopCounter: indicates the index in the for each loop of that particular instance
    To make an activity multi-instance, the activity xml element must have a multiInstanceLoopCharacteristics child element.

The isSequential attribute indicates if the instances of that activity are executed sequentially or in parallel.

The number of instances are calculated once, when entering the activity. There are a few ways of configuring this. On way is directly specifying a number by using the loopCardinality child element.

  1. <multiInstanceLoopCharacteristics isSequential="false|true">
  2. <loopCardinality>5</loopCardinality>
  3. </multiInstanceLoopCharacteristics>

Expressions that resolve to a positive number are also possible:

  1. <multiInstanceLoopCharacteristics isSequential="false|true">
  2. <loopCardinality>${nrOfOrders-nrOfCancellations}</loopCardinality>
  3. </multiInstanceLoopCharacteristics>

Suppose the variable assigneeList contains the values [kermit, gonzo, foziee]. In the snippet above, three user tasks will be created in parallel. Each of the executions will have a process variable named assignee containing one value of the collection, which is used to assign the user task in this example.

The downside of the loopDataInputRef and is that 1) the names are pretty hard to remember and 2) due to the BPMN 2.0 schema restrictions they can’t contain expressions. We solve this by offering the collection and elementVariable attributes on the multiInstanceCharacteristics:

  1. <userTask id="miTasks" name="My Task" camunda:assignee="${assignee}">
  2. camunda:collection="${myService.resolveUsersForTask()}" camunda:elementVariable="assignee" >
  3. </multiInstanceLoopCharacteristics>
  4. </userTask>

A multi-instance activity ends when all instances are finished. However, it is possible to specify an expression that is evaluated every time one instance ends. When this expression evaluates to true, all remaining instances are destroyed and the multi-instance activity ends, continuing the process. Such an expression must be defined in the completionCondition child element.

  1. <userTask id="miTasks" name="My Task" camunda:assignee="${assignee}">
  2. <multiInstanceLoopCharacteristics isSequential="false"
  3. camunda:collection="assigneeList" camunda:elementVariable="assignee" >
  4. <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6 }</completionCondition>
  5. </multiInstanceLoopCharacteristics>
  6. </userTask>

In this example, parallel instances will be created for each element of the assigneeList collection. However, when 60% of the tasks are completed, the other tasks are deleted and the process continues.

Since a multi-instance is a regular activity, it is possible to define a boundary event on its boundary. In case of an interrupting boundary event, when the event is caught, all instances that are still active will be destroyed. For example, take the following multi-instance subprocess:

Here all instances of the subprocess will be destroyed when the timer fires, regardless of how many instances there are or which inner activities are currently not completed yet.

The loop marker is not natively supported yet by the engine. For Multiple Instance, the number of repetitions is known in advance - which makes it a bad candidate for loops anyway, as it defines a completion condition that may already be sufficient in some cases.

To get around this limitation, the solution is to explicitly model the loop in your BPMN process:

JSON Arrays created with can be used as a collection for multi-instance activities.Consider the following JavaScript example that initializes execution variable collection:

This script can be injected in the model in several ways, e.g. using Script task.

We can now use collection variable in multi-instance activity’s camunda:collection extension element.

  1. <multiInstanceLoopCharacteristics
  2. camunda:collection="${collection.prop('collection').elements()}"
  3. camunda:elementVariable="collectionElem" />

This uses the SPIN’s JSON .prop() and .elements() to return the JSON array. Set the multi-instance activity’s elementVariable to a variable name thatwill contain the array item. To access the value of the element, you can use .value() in your element variable.

Compensation

If an activity is used for compensating the effects of another activity, it can be declared to be a compensation handler. Compensation handlers are not contained in the regular flow and are only executed when a compensation event is thrown.

Notice the compensation handler icon in the bottom center area of the “cancel hotel reservation” service task.

Compensation handlers may not have incoming or outgoing sequence flows.

A compensation handler must be associated with a compensation boundary event using a directed association.

Additional Resources