1, Start event
1.1. Empty start event
Illustration:
Description: A "none Start Event" refers to a start event that does not specify a trigger to start a process instance. The engine will not know when to start the process instance.
Note: the sub process must have an empty start event.
Code example:
java: ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX(); xml: <startEvent id="start" name="my start event" /> <!--formKey: Refer to the form definition. Users need to fill in the form when starting a new process instance--> <startEvent id="request" flowable:formKey="request" />
1.2 timer start event
Figure: (timer event on modeler)
Description: timer start event creates a process instance at a specified time. It can be used when the process only needs to be started once, or when the process needs to be started repeatedly at a specific time interval.
Note: the process cannot have timer start event. The timer starts the event and starts timing when the process is deployed. There is no need to call startProcessInstanceByXXX to start at time. When calling startProcessInstanceByXXX, an additional process will be started in addition to the scheduled start. When you deploy an updated version of a process with a timer start event, the timer job of the previous version is removed. This is because you usually don't want old versions of the process to automatically start new process instances.
Code example:
<!--Example: the process will be started 4 times, with an interval of 5 minutes, from November 11, 2011 to December 12, 2011:13 start--> <startEvent id="theStart"> <timerEventDefinition> <timeCycle>R4/2021-11-11T12:13/PT5M</timeCycle> </timerEventDefinition> </startEvent> <!--Example: the process will start once at the set time--> <startEvent id="theStart"> <timerEventDefinition> <timeDate>2021-11-11T12:13:14</timeDate> </timerEventDefinition> </startEvent>
1.3. Message start event
Illustration:
Description: the message start event starts the process instance with a named message. The message name is used to select the correct startup event.
Note: when deploying a process definition with one or more message initiation events, the following judgment will be made:
-
The name of the message initiation event must be unique in the given process definition. A process definition cannot contain multiple message initiation events with the same name. If two or more message start events in the process definition refer to the same message, or two or more message start events refer to messages with the same message name, Flowable will throw an exception when deploying the process definition.
-
In all deployed process definitions, the name of the message initiation event must be unique. If one or more message start events in a process definition refer to the message name of the message start event in another deployed process definition, Flowable will throw an exception when deploying this process definition.
-
Process version: when deploying a new version of the process definition, the message subscription of the previous version will be cancelled, even if there is no message event in the new version).
When starting a process instance, you can use the following methods in RuntimeService to trigger a message start event:
ProcessInstance startProcessInstanceByMessage(String messageName); ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables); ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object< processVariables);
messageName is the name given by the name attribute of the message element. The messageRef attribute of messageEventDefinition refers to the message element. When a process instance is started, the following judgment will be made:
-
Only top-level process es support message initiation events. Embedded subprocesses do not support message start events.
-
If there are multiple message start events in a process definition, you can use runtimeService.startProcessInstanceByMessage(...) to select the appropriate start event.
-
If there are multiple message start events and one empty start event in a process definition, runtimeService.startProcessInstanceByKey(...) and runtimeService.startProcessInstanceById(...) will start the process instance with the empty start event.
-
If there are multiple message start events but no empty start events in a process definition, runtimeService.startProcessInstanceByKey(...) and runtimeService.startProcessInstanceById(...) will throw exceptions.
-
If there is only one message start event in a process definition, runtimeService.startProcessInstanceByKey(...) and runtimeService.startProcessInstanceById(...) will use this message start event to start a new process instance.
-
If a process is started by a call activity, the message start event is supported only if
-
In addition to the message start event, the process has a unique empty start event
-
Or the process has only a unique message start event and no other start events.
-
Code example:
<definitions id="definitions" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="Examples" xmlns:tns="Examples"> <message id="newInvoice" name="newInvoiceMessage" /> <process id="invoiceProcess"> <startEvent id="messageStart" > <messageEventDefinition messageRef="tns:newInvoice" /> </startEvent> ... </process> </definitions>
1.4 signal start event
Illustration:
Description: signal start event, which uses a named signal to start a process instance. This signal can be triggered by the signal in the process instance throwing an intermediate signal throw event or API (runtimeService.signalEventReceivedXXX method). Both methods will start all process definitions of signal start events with the same name.
Note: you can choose to start process instances asynchronously or synchronously. The signalName to be passed to the API is the name determined by the name attribute of the signal element. The signal element is referenced by the signalRef attribute of the signalEventDefinition
Code example:
<signal id="theSignal" name="The Signal" /> <process id="processWithSignalStart1"> <startEvent id="theStart"> <signalEventDefinition id="theSignalEventDefinition" signalRef="theSignal" /> </startEvent> <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" /> <userTask id="theTask" name="Task in process A" /> <sequenceFlow id="flow2" sourceRef="theTask" targetRef="theEnd" /> <endEvent id="theEnd" /> </process>
1.6. Error startup event
Illustration:
Description: error start event, which can be used to trigger event sub process. The error start event cannot be used to start a process instance.
Note: error start events are always interrupted.
Code example:
<!--ref It refers to a task event--> <startEvent id="messageStart" > <errorEventDefinition errorRef="someError" /> </startEvent>
2, End event
Description: an end event marks the end of a branch in a process or sub process. End events always throw (type) events. This means that when the process execution reaches the end event, a result will be thrown. The type of result is represented by a black Icon inside the event. In XML representation, types are given by child element declarations.
2.1. Empty end event
Illustration:
Description: a "none end event" means that when this event is reached, the result thrown is not specified. Therefore, the engine will do nothing more than end the current branch.
Code example:
<endEvent id="end" name="my end event" />
2.2. Error end event
Illustration:
Description: when the process execution reaches the error end event, the current branch of the execution is ended and an error is thrown. This error can be captured by a matching error boundary intermediate event. If no matching error boundary event is found, an exception is thrown.
Code example:
<!--error of errorCode Used to find matching error capture boundary events. If errorRef Does not match any defined error,Then errorRef Can be used as errorCode Shortcut to. This shortcut is Flowable Unique.--> <error id="myError" errorCode="error123" /> ... <process id="myProcess"> ... <endEvent id="myErrorEndEvent"> <errorEventDefinition errorRef="myError" /> </endEvent> ...
2.3 termination event
Illustration:
Description: when the terminate end event is reached, the current process instance or sub process will be terminated. That is, when the execution reaches the termination end event, the first scope (process or sub process) will be judged and terminated. Note that in BPMN 2.0, a sub process can be an embedded sub process, an invocation activity sub process, an event sub process, or a transaction sub process. There is a general rule: when there are multiple instance calling procedures or embedded sub processes, only one instance will be terminated, and other instances and process instances will not be affected.
You can add an optional attribute terminateAll. When it is true, the (root) process instance will be terminated no matter where the termination end event is in the process definition or whether it is in a sub process (or even an embedded sub process).
Code example:
<!--Termination end event, expressed as an end event, plus terminateEventDefinition Child element. Please note that terminateAll Property is optional (the default is false). --> <endEvent id="myEndEvent > <terminateEventDefinition flowable:terminateAll="true"></terminateEventDefinition> </endEvent>
2.4. Cancel end event
Illustration:
Description: the cancel end event can only be used with the BPMN transaction subprocess. When the cancel end event is reached, a cancel event will be thrown and must be captured by the cancel boundary event. The cancel boundary event will cancel the transaction and trigger compensation.
Code example:
<endEvent id="myCancelEndEvent"> <cancelEventDefinition /> </endEvent>
3, Boundary event
Description: a boundary event is a captured event attached to an activity. A boundary event will never be thrown. This means that when an activity runs, the event will listen for a specific type of trigger. When an event is captured, the activity will terminate and continue along the exit sequence of the event.
<!-- All boundary events are defined in the same way --> <boundaryEvent id="myBoundaryEvent" attachedToRef="theActivity"> <XXXEventDefinition/> </boundaryEvent>
Boundary events are defined by the following elements:
-
Unique identifier (within the process scope)
-
The reference to the activity to which the event is attached, as defined by the attachedToRef property. Note that boundary events and their attached activities should be defined at the same level (that is, boundary events are not included in activities).
-
XML sub elements that define the type of boundary events, such as XXXEventDefinition (e.g. timerevendefinition, errorevendefinition, etc.).
3.1 timer boundary event
Boundary event problem:
All types of boundary events have a known problem about Concurrency: multiple exit sequence streams cannot be attached to boundary events. The solution to this problem is to use an exit sequence stream to point to parallel gateways.
Illustration: (this diagram should be wrong according to the instructions continued above.)
Description: the timer boundary event behaves like a running watch and an alarm clock. When the activity to which the boundary event is attached is executed, the timer will be started. When the timer is triggered (for example, after a specific time interval), the activity can be interrupted and the execution can continue along the exit sequence flow of the boundary event.
Code example:
<!--Timer boundary events are defined like general boundary events. The type sub element is timerEventDefinition Element. <boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport"> <timerEventDefinition> <timeDuration>PT4H</timeDuration> </timerEventDefinition> </boundaryEvent>
Example 2:
Boundary event problem:
All types of boundary events have a known problem about Concurrency: multiple exit sequence streams cannot be attached to boundary events. The solution to this problem is to use an exit sequence stream to point to parallel gateways.
Illustration:
Description: interrupt and non interrupt timer events are different. Non interrupt means that the initial activity will not be interrupted, but will remain the same. The default is interrupt behavior. In the XML representation, the cancelActivity property is set to false.
A typical usage scenario is to send a reminder email after a period of time, but it does not affect the normal flow direction.
Note: timer boundary events can only be triggered when asynchronous executor is enabled (that is, asyncExecutorActivate needs to be set to true in flowable.cfg.xml, because asynchronous executor is disabled by default.)
Code example:
<boundaryEvent id="escalationTimer" cancelActivity="false" attachedToRef="firstLineSupport"/>
3.2. Error boundary event
Illustration:
Description: the error capture intermediate (event) on the activity boundary, or error boundary event for short, captures the errors thrown within the activity scope to which it is attached.
It is most meaningful to define error boundary events on embedded subprocesses or calling activities, because the scope of subprocesses will include all activities in them. Errors can be thrown by error end events. Such errors will propagate layer by layer to their parent scope until an error boundary event matching the definition of error events is found in the scope.
When an error event is captured, the activity in which the boundary event definition is located will be destroyed, and all current executions (for example, parallel activities, nested sub processes, etc.) will be destroyed. Process execution will continue along the exit sequence flow of boundary events.
Code example:
<error id="myError" errorCode="123" /> ... <process id="myProcess"> ... <boundaryEvent id="catchError" attachedToRef="mySubProcess"> <errorEventDefinition errorRef="myError"/> </boundaryEvent>
be careful:
errorCode is used to match captured errors:
-
If errorRef is omitted, the error boundary event captures all error events, regardless of the errorCode of the error.
-
If errorRef is provided and it references an existing error, the boundary event will only catch errors with the same error code.
-
If errorRef is provided but error is not defined in the BPMN 2.0 file, errorRef is used as errorCode (similar to the error end event).
Example:
The following example process shows how to use the error end event. When the 'Review profitability' user task is completed and indicates that the information provided is insufficient, an error will be thrown. When this error is captured by the sub process boundary, all running activities in the 'Review sales lead' sub process will be destroyed (even if 'Review customer rating' has not been completed), and a 'Provide additional details' user task will be created.
3.3 signal boundary events
Illustration:
Description: the signal capture intermediate (event) attached to the activity boundary, or signal boundary event for short, captures a signal with the same name as its signal definition.
Please note: unlike other events such as error boundary events, signal boundary events do not just capture the signals thrown by the scope to which they are attached. Signal boundary events are global (broadcast), which means that signals can be thrown from anywhere, or even different process instances.
Unlike other events, such as error events, signals are not consumed after being captured. If two active signal boundary events capture the same signal event, both boundary events will be triggered, even if they are not in the same process instance.
Code example:
<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true"> <signalEventDefinition signalRef="alertSignal"/> </boundaryEvent>
3.4 signal boundary events
Illustration: (it is said that there is also a non disruptive message boundary event, which I can't find on the modeler.)
Description: the message capture intermediate (event) on the activity boundary, or message boundary event for short, captures a message with the same message name as its message definition.
Code example:
<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true"> <messageEventDefinition messageRef="newCustomerMessage"/> </boundaryEvent>
3.5. Cancel boundary event
Illustration:
Description: the cancel capture intermediate event attached to the transaction sub process boundary, or the cancel boundary event for short, is triggered when the transaction is cancelled. When the cancel boundary event is triggered, the execution of all activities in the current range will be interrupted first. Next, start all valid compensation boundary event s within the transaction scope. The compensation will be executed synchronously, that is, before leaving the transaction, the boundary event will wait for the compensation to complete. When compensation is complete, the flow leaves the transaction subprocess along any exit sequence of the cancel boundary event.
Note: only one cancellation boundary event is allowed for a transaction sub process.
If there are nested subprocesses in the transaction subprocess, compensation will only be triggered for the successfully completed subprocess.
If the cancellation boundary event is placed on a transaction sub process with multi instance characteristics, if an instance triggers cancellation, the boundary event will cancel all instances.
Code example:
<!--Because the cancel boundary event is always interrupt type, there is no cancelActivity Properties.--> <boundaryEvent id="boundary" attachedToRef="transaction" > <cancelEventDefinition /> </boundaryEvent>
3.5 compensation boundary events
Illustration:
Description: the compensation capture intermediate (event) attached to the activity boundary, or compensation boundary event for short, can add a compensation processor to the activity.
Compensation boundary events must reference a single compensation processor in a direct correlation manner.
The activity strategy of compensating boundary events is different from that of other boundary events. Other boundary events, such as signal boundary events, are activated when the activity to which they are attached is started; When the activity ends, it will be cancelled and the corresponding event subscription will be cancelled. This is not the case with compensation boundary events. The compensation boundary event is activated when its dependent activity completes successfully, and the corresponding subscription of the compensation event is created. The subscription is removed only when the compensation event is triggered or the corresponding process instance ends. Please consider the following factors:
-
When compensation is triggered, the compensation processor associated with the compensation boundary event is called. The number of calls is the same as the number of successful completion of its dependent activity.
-
If compensation boundary events are attached to activities with multi instance characteristics, compensation event subscriptions are created for each instance.
-
If the compensation boundary event is attached to an activity inside the loop, a compensation event subscription is created each time the activity executes.
-
If the process instance ends, the subscription to the compensation event is cancelled.
Note: the embedded subprocess does not support compensation boundary events.
Code example:
<!--Because the cancel boundary event is always interrupt type, there is no cancelActivity Properties.--> <boundaryEvent id="boundary" attachedToRef="transaction" > <cancelEventDefinition /> </boundaryEvent>
4, Capture intermediate events
All intermediate catching events are defined in the same way:
<intermediateCatchEvent id="myIntermediateCatchEvent" > <XXXEventDefinition/> </intermediateCatchEvent>
Capture intermediate events are defined by the following elements:
-
Unique identifier (within the process scope)
-
Defines XML sub elements (such as timerevendefinition) that capture intermediate event types, such as XXXEventDefinition. Review the specific intermediate capture event types for more details.
4.1 timer captures intermediate events
Illustration
Description: timer intermediate catching event acts like running a watch. When the execution reaches the capture event, start the timer; When the timer is triggered (e.g. after a period of time interval), execution continues along the exit sequence flow of timer intermediate events.
Code example:
<intermediateCatchEvent id="timer"> <timerEventDefinition> <timeDuration>PT5M</timeDuration> </timerEventDefinition> </intermediateCatchEvent>
4.2 intermediate event of signal acquisition
Illustration
Description: signal intermediate catching event, which captures signals with the same signal name as the referenced signal definition.
Note: unlike other events such as error events, signals are not consumed after being captured. If two active signal intermediate events capture the same signal event, both intermediate events will be triggered, even if they are not in the same process instance
Code example:
<intermediateCatchEvent id="signal"> <signalEventDefinition signalRef="newCustomerSignal" /> </intermediateCatchEvent>
4.3 message capture intermediate events
Illustration
Description: message intermediate catching event, which captures messages with specific names.
Code example:
<intermediateCatchEvent id="message"> <messageEventDefinition signalRef="newCustomerMessage" /> </intermediateCatchEvent>
5. Throw intermediate event
All intermediate throwing evnet events are defined in the same way:
<intermediateThrowEvent id="myIntermediateThrowEvent" > <XXXEventDefinition/> </intermediateThrowEvent>
Throwing an intermediate event is defined by the following elements:
-
Unique identifier (within the process scope)
-
Defines the XML sub elements (such as signalEventDefinition) that throw intermediate event types, such as XXXEventDefinition.
5.1. Empty throw intermediate event
Figure: the following flowchart shows a simple example of an intermediate throwing none event. It is used to indicate that the process has reached a certain state.
You can also add your own code to send some events to your BAM (Business Activity Monitoring) tool or DWH (Data Warehouse). In this case, the engine itself will not do anything, just pass through it.
<!--After adding an execution listener, air events can become a good monitor KPI(Key Performance Indicators Key performance indicators)--> <intermediateThrowEvent id="noneEvent"> <extensionElements> <flowable:executionListener class="org.flowable.engine.test.bpmn.event.IntermediateNoneEventTest$MyExecutionListener" event="start" /> </extensionElements> </intermediateThrowEvent>
5.2. Signal throwing intermediate event
Illustration:
Description: the signal throws an intermediate throwing event to throw the signal event of the defined signal.
In Flowable, signals are broadcast to all active processors (that is, all signal capture events). Signals can be issued synchronously or asynchronously.
-
In the default configuration, signals are transmitted synchronously. This means that the process instance that throws the signal will wait until the signal is passed to all the process instances that capture the signal. All captured process instances will also be in the same transaction as the thrown process instance, that is, if one of the notified process instances generates a technical error (throws an exception), all relevant instances will fail.
-
Signals can also be transmitted asynchronously. This is determined by the sending processor when the signal event is thrown. For each activated processor, JobExecutor will store and deliver an asynchronous notification message, namely Job.
<!--Synchronization signal event--> <intermediateThrowEvent id="signal"> <signalEventDefinition signalRef="newCustomerSignal" /> </intermediateThrowEvent> <!--Asynchronous signal event--> <intermediateThrowEvent id="signal"> <signalEventDefinition signalRef="newCustomerSignal" flowable:async="true" /> </intermediateThrowEvent>
5.3. Compensation throws intermediate events
Illustration:
(refer to flowable6.3.0 Modeler in this document. Use 6.5.0 to check whether this event is deleted.)
Description: compensation intermediate throwing event is used to trigger compensation.
Trigger compensation: it can trigger compensation for both the designed activity and the range of compensation events. Compensation is performed by the compensation processor associated with the activity.
-
When the activity throws compensation, the number of times the compensation processor associated with the activity will execute is the number of times the activity is successfully completed.
-
When compensation is thrown, all activities in the current scope, including those on parallel branches, are compensated.
-
Compensation layered trigger: if the activity to be compensated is a sub process, all activities in the sub process will trigger compensation. If the subprocess has nested activities, compensation will be thrown recursively. However, compensation is not propagated to the upper layer of the process: if compensation is triggered in the sub process, the compensation is not propagated to activities outside the scope of the sub process. The BPMN specification states that compensation is triggered for activities "at the same level as sub processes".
-
In Flowable, compensation runs in the reverse order of execution. This means that the last completed activity will be compensated first.
-
You can use compensation to throw intermediate events to compensate the transaction subprocess that has completed successfully.
Note: if there is a subprocess in the scope of throwing compensation and the subprocess contains activities related to the compensation processor, when throwing compensation, the compensation will not be propagated to the subprocess until the subprocess is successfully completed. If some activities embedded in the subprocess have been completed and compensation processors have been attached, but the subprocess containing these activities has not been completed, these compensation processors will not be executed.
<!--Synchronization signal event--> <intermediateThrowEvent id="signal"> <signalEventDefinition signalRef="newCustomerSignal" /> </intermediateThrowEvent> <!--Asynchronous signal event--> <intermediateThrowEvent id="signal"> <signalEventDefinition signalRef="newCustomerSignal" flowable:async="true" /> </intermediateThrowEvent>
6. Sequential flow
Illustration
Description: sequence flow is a connector between two elements in a process. In the process of process execution, after an element is accessed, it will continue to execute along all its exit sequence flows. This means that BPMN 2.0 is executed in parallel by default: two exit sequence flows will create two independent and parallel execution paths.
Code example
<!--Sequential flow needs to have a unique process id,And reference the existing source and target elements. --> <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />
6.1 conditional sequence flow
Description: a conditional sequence flow can be defined on a sequential flow. When leaving a BPMN 2.0 activity, the default behavior is to calculate the conditions on each of its exit sequence flows. When the condition evaluates to true, select the exit sequence flow. If the method selects multiple sequential flows, multiple executions will be generated and the process will continue in parallel.
Note: the above description is for BPMN 2.0 activities (and events), but not for gateways. Different types of gateways deal with conditional sequential flows in different ways.
Code example
<sequenceFlow id="flow" sourceRef="theStart" targetRef="theTask"> <conditionExpression xsi:type="tFormalExpression"> <![CDATA[${order.price > 100 && order.price < 250}]]> </conditionExpression> </sequenceFlow>
Currently, conditional expressions can only use UEL. Details can be found in expression Chapter found. The expression used needs to be able to resolve to a boolean value, otherwise an exception will be thrown when calculating the condition.
<!--Through typical JavaBean How to use getter Data referencing process variables.--> <conditionExpression xsi:type="tFormalExpression"> <![CDATA[${order.price > 100 && order.price < 250}]]> </conditionExpression> <!--Through typical JavaBean How to use getter Data referencing process variables.--> <conditionExpression xsi:type="tFormalExpression"> <![CDATA[${order.isStandardOrder()}]]> </conditionExpression>
6.2. Default sequence flow
Description: all BPMN 2.0 tasks and gateways can use the default sequence flow. The default sequence flow is selected as the active exit sequence flow only when there are no other sequence flows to choose from. The process ignores the conditions on the default sequential flow
Note: the default sequence flow of an activity is defined by the default attribute of the activity. The following XML fragment shows an exclusive gateway with the default sequential flow 2. Only when both conditionA and conditionB are calculated as false, the default sequence flow will be selected as the gateway's exit sequence flow.
Code example
<exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" default="flow2" /> <sequenceFlow id="flow1" sourceRef="exclusiveGw" targetRef="task1"> <conditionExpression xsi:type="tFormalExpression">${conditionA}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="task2"/> <sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="task3"> <conditionExpression xsi:type="tFormalExpression">${conditionB}</conditionExpression> </sequenceFlow>
7, gateway
The gateway is used to control the flow of execution (or "token" of execution according to the term of BPMN 2.0). The gateway can consume and generate flags.
The gateway is represented by a diamond with an icon. This icon shows the type of gateway.
7.1. Exclusive gateway
Illustration
Description: exclusive gateway (also called XOR gateway, or more professional exclusive data-based gateway) is used to model decisions in the process. When the execution reaches the gateway, they are calculated in the order defined by all exit flows. Select the sequence flow whose first condition is calculated to be true (when no condition is set, the sequence flow is considered to be true) to continue the process.
Note: the meaning of exit sequence flow here is different from the general situation in BPMN 2.0. Generally, all sequential streams whose conditions are calculated as true will be selected and executed in parallel. When using an exclusive gateway, only one sequential flow will be selected. When the conditions of multiple sequential flows are evaluated as true, only the sequential flow first defined in XML will be selected to continue the process. If there is no optional sequential flow, an exception is thrown.
The XML representation of the exclusive gateway is concise: one line defines the XML of the gateway. A conditional expression is defined on its exit sequence stream.
Code example
exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" /> <sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1"> <conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2"> <conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3"> <conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression> </sequenceFlow>
7.2 parallel gateway
Illustration
Description: the gateway can also model parallel execution in a process. The simplest gateway to introduce parallelism into the process model is the parallel gateway. It can fork the execution into multiple paths or join the execution of multiple entry paths.
The function of parallel gateway depends on its entry and exit sequence flow:
-
Branch: all exit sequence flows are executed in parallel, and a parallel execution is created for each sequence flow.
-
Merge: all parallel executions arriving at the parallel gateway will wait at the gateway until each entry sequence flow reaches an execution. The process then continues through the merge gateway.
Note that if the parallel gateway has multiple entry and exit sequential flows at the same time, it can have the behavior of branching and merging at the same time. In this case, the gateway first merges all entry sequential flows, and then splits them into multiple parallel execution paths.
There is an important difference from other gateway types: parallel gateways do not compute conditions. If a condition is defined on a sequential flow connected to a parallel gateway, the condition is ignored directly.
Code example
<!--Only one line is required to define a parallel gateway XML--> <parallelGateway id="myParallelGateway" /> <!--The actual behavior (branch, merge, or both) is defined by the sequential flow connected to the parallel gateway. For example, the model above is represented by the model below XML--> <startEvent id="theStart" /> <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" /> <parallelGateway id="fork" /> <sequenceFlow sourceRef="fork" targetRef="receivePayment" /> <sequenceFlow sourceRef="fork" targetRef="shipOrder" /> <userTask id="receivePayment" name="Receive Payment" /> <sequenceFlow sourceRef="receivePayment" targetRef="join" /> <userTask id="shipOrder" name="Ship Order" /> <sequenceFlow sourceRef="shipOrder" targetRef="join" /> <parallelGateway id="join" /> <sequenceFlow sourceRef="join" targetRef="archiveOrder" /> <userTask id="archiveOrder" name="Archive Order" /> <sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" /> <endEvent id="theEnd" />
In the above example, two tasks will be created after the process is started:
ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin"); TaskQuery query = taskService.createTaskQuery() .processInstanceId(pi.getId()) .orderByTaskName() .asc(); List<Task> tasks = query.list(); assertEquals(2, tasks.size()); Task task1 = tasks.get(0); assertEquals("Receive Payment", task1.getName()); Task task2 = tasks.get(1); assertEquals("Ship Order", task2.getName());
be careful:
When the two tasks are completed, the second parallel gateway will merge the two executions. Since it has only one exit sequence flow, it will no longer create parallel execution paths, but only activate the archive order task.
Please note that parallel gateways do not need to be "balanced" (that is, the number of inlet / outlet sequential flows of the two corresponding parallel gateways does not need to be consistent). Each parallel gateway simply waits for all entry sequential flows and creates parallel execution for each exit sequential flow, independent of other structures in the process model. Therefore, the following process is legal in BPMN 2.0:
7.3. Containment gateway
Illustration:
Description: the inclusive gateway can be regarded as a combination of exclusive gateway and parallel gateway. Like the exclusive gateway, conditions can be defined on the exit sequence flow of the containing gateway, and the containing gateway will calculate the conditions. However, the main difference is that the inclusive gateway can select more than one exit sequence flow at the same time as the parallel gateway.
The function of the containment gateway depends on its entry and exit sequence flow:
-
Branch: the process calculates the conditions for all exit sequence flows. For each sequential flow that evaluates to true, the process creates a parallel execution.
-
Merge: all parallel executions arriving at the containment gateway will wait at the gateway. Until each entry sequence flow with process token has an execution arrival. This is an important difference from parallel gateway. In other words, the containment gateway will only wait for the entry sequence flow that can be executed. After the merge, the process continues through the merge parallel gateway.
Note that if the containment gateway has multiple entry and exit sequential flows at the same time, it can have the behavior of branching and merging at the same time. In this case, the gateway first merges all the entry sequential flows with process flags, and then splits the parallel execution path for each exit sequential flow whose condition is calculated as true. The aggregation behavior of inclusive gateway is more complex than that of parallel gateway. All parallel executions arriving at the containment gateway will wait at the gateway until all "reachable" containment gateway executions "arrive" at the containment gateway. The judgment method is to calculate all executions in the current process instance and check whether there is a path from its location to the containment gateway (ignoring any conditions on the sequential flow). If there is such an execution (reachable but not yet reached), the aggregation behavior of the containment gateway will not be triggered.
<!--Only one line is required to define the containment gateway XML--> <inclusiveGateway id="myInclusiveGateway" /> <!--The actual behavior (branch, merge, or both) is defined by the sequential flow connected to the containment gateway.--> <startEvent id="theStart" /> <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" /> <inclusiveGateway id="fork" /> <sequenceFlow sourceRef="fork" targetRef="receivePayment" > <conditionExpression xsi:type="tFormalExpression">${paymentReceived == false}</conditionExpression> </sequenceFlow> <sequenceFlow sourceRef="fork" targetRef="shipOrder" > <conditionExpression xsi:type="tFormalExpression">${shipOrder == true}</conditionExpression> </sequenceFlow> <userTask id="receivePayment" name="Receive Payment" /> <sequenceFlow sourceRef="receivePayment" targetRef="join" /> <userTask id="shipOrder" name="Ship Order" /> <sequenceFlow sourceRef="shipOrder" targetRef="join" /> <inclusiveGateway id="join" /> <sequenceFlow sourceRef="join" targetRef="archiveOrder" /> <userTask id="archiveOrder" name="Archive Order" /> <sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" /> <endEvent id="theEnd" />
In the above example, after the process is started, if the process variable paymentReceived == false and shipOrder == true, two tasks will be created. If only one process variable is equal to true, only one task will be created. If no condition evaluates to true, an exception will be thrown (which can be avoided by specifying the default exit sequence flow). In the following example, only one ship order task will be created
HashMap<String, Object> variableMap = new HashMap<String, Object>(); variableMap.put("receivedPayment", true); variableMap.put("shipOrder", true); ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin"); TaskQuery query = taskService.createTaskQuery() .processInstanceId(pi.getId()) .orderByTaskName() .asc(); List<Task> tasks = query.list(); assertEquals(1, tasks.size()); Task task = tasks.get(0); assertEquals("Ship Order", task.getName());
When this task is completed, the second containment gateway will merge the two executions. Moreover, since it has only one exit sequence flow, the parallel execution path will not be created, but only the archive order task will be activated.
Please note that the containment gateway does not need to be "balanced" (that is, the number of inlet / outlet sequential flows of the corresponding containment gateway does not need to be matched). The containment gateway simply waits for all entry sequential flows and creates parallel execution for each exit sequential flow, which is not affected by other structures in the process model.
Please note that the containment gateway does not need to be "balanced" (that is, the number of inlet / outlet sequential flows of the two corresponding containment gateways does not need to be consistent). Each containment gateway simply waits for all entry sequential flows and creates parallel execution for each exit sequential flow, which is not affected by other structures in the process model.
7.4 event based gateway
Figure: the following is an example process with an event based gateway. When execution reaches the event based gateway, process execution is suspended. The process instance subscribes to the alert signal event and creates a timer that will trigger after 10 minutes. The process engine will wait for 10 minutes and wait for signal events at the same time. If the signal is triggered within 10 minutes, the timer will be cancelled, and the process continues along the signal to activate the Handle alert user task. If there is no trigger signal within 10 minutes, the execution will continue and the signal subscription will be cancelled.
Description: event based gateway provides a way to select based on events. Each exit sequence flow of the gateway needs to be connected to a capture intermediate event. When the process execution reaches the event based gateway, similar to the waiting state, the gateway pauses the execution and creates an event subscription for each exit sequence flow.
Please note that the exit sequence flow of event based gateway is different from the general sequence flow. These sequential flows are never actually executed. Instead, they are used to tell the process engine what events to subscribe to when execution reaches an event based gateway. There are the following limitations:
-
An event based gateway must have two or more exit sequence flows.
-
Event based gateways can only be connected to elements of type intermediateCatchEvent (Flowable does not support connecting "Receive Task" after event based gateways).
-
The intermediateCatchEvent connected to the event based gateway must have only one entry sequence flow.
Code example:
<definitions id="definitions" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="Examples"> <signal id="alertSignal" name="alert" /> <process id="catchSignal"> <startEvent id="start" /> <sequenceFlow sourceRef="start" targetRef="gw1" /> <eventBasedGateway id="gw1" /> <sequenceFlow sourceRef="gw1" targetRef="signalEvent" /> <sequenceFlow sourceRef="gw1" targetRef="timerEvent" /> <intermediateCatchEvent id="signalEvent" name="Alert"> <signalEventDefinition signalRef="alertSignal" /> </intermediateCatchEvent> <intermediateCatchEvent id="timerEvent" name="Alert"> <timerEventDefinition> <timeDuration>PT10M</timeDuration> </timerEventDefinition> </intermediateCatchEvent> <sequenceFlow sourceRef="timerEvent" targetRef="exGw1" /> <sequenceFlow sourceRef="signalEvent" targetRef="task" /> <userTask id="task" name="Handle alert"/> <exclusiveGateway id="exGw1" /> <sequenceFlow sourceRef="task" targetRef="exGw1" /> <sequenceFlow sourceRef="exGw1" targetRef="end" /> <endEvent id="end" /> </process> </definitions>