Hey,
I want to model a process that waits for all of its participants to reach a certain final state. I designed this by creating a process that has a process variable that counts the number of participants that are not yet in that state. Each time a participant reaches the final state, it sends a message to the process instance. The process handles such messages by a non-interrupting event subprocess that runs a simple service that decrements the counter and checks if it reached zero. Simple enough.
However, I want to make sure this runs efficiently in situations where many of the participants reach the final state at the same time. A naive implementation will result in many optimistic locking exceptions with associated retries.
So I made the service async. That works and avoids optimistic locking exceptions but is also horribly slow as the service is only executed once every time flowable queries for jobs (= by default once every 10s).
Is there a better way to express this in BPMN? The alternative is that I implement some synchronization mechanism (e.g. based on database locks) in Java code of the participants such that they don’t send messages concurrently and not declare the service as async.
PS: Here’s my process def.
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:flowable="http://flowable.org/bpmn"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
targetNamespace="Examples">
<signal id="counterZeroSignal" name="CounterZero" />
<message id="countDownMessage" name="CountDown" />
<process id="counting-process">
<startEvent id="start-main">
<outgoing>Flow_0jsk20j</outgoing>
</startEvent>
<subProcess id="count-activity" triggeredByEvent="true">
<startEvent id="start-decrement" **isInterrupting="false"**>
<outgoing>Flow_0csobbx</outgoing>
<messageEventDefinition messageRef="countDownMessage" />
</startEvent>
<sequenceFlow id="Flow_0csobbx" sourceRef="start-decrement" targetRef="count-service" />
<serviceTask id="count-service" name="Count" flowable:delegateExpression="${countServiceTask}" **flowable:async="true"**>
<incoming>Flow_0csobbx</incoming>
<outgoing>Flow_1sry4ac</outgoing>
</serviceTask>
<endEvent id="end-decrement">
<incoming>Flow_1sry4ac</incoming>
</endEvent>
<sequenceFlow id="Flow_1sry4ac" sourceRef="count-service" targetRef="end-decrement" />
</subProcess>
<intermediateCatchEvent id="catch-signal">
<incoming>Flow_0jsk20j</incoming>
<outgoing>Flow_1dxixqo</outgoing>
<signalEventDefinition signalRef="counterZeroSignal" />
</intermediateCatchEvent>
<sequenceFlow id="Flow_0jsk20j" sourceRef="start-main" targetRef="catch-signal" />
<sequenceFlow id="Flow_1dxixqo" sourceRef="catch-signal" targetRef="complete-service" />
<serviceTask id="complete-service" name="Complete" flowable:delegateExpression="${completeServiceTask}">
<incoming>Flow_1dxixqo</incoming>
<outgoing>Flow_13cbiu0</outgoing>
</serviceTask>
<endEvent id="main-end">
<incoming>Flow_13cbiu0</incoming>
</endEvent>
<sequenceFlow id="Flow_13cbiu0" sourceRef="complete-service" targetRef="main-end" />
</process>
</definitions>