Race condition for parallel multi instance user tasks

It is a common case which uses parallel multi instance user tasks to collect some variables and decides the next step. Just as the following process:


some person review the task and make their choice, and the next task is just based on whether all of them approve the task or not. Let’s say, if a person approve his task, the approvedCount variable will be plused one(approvedCount = approvedCount + 1).

The problem is that the user task is parallel multi instance which means two or more person may complete their use task at the same time. If it happens, the variable approvedCount in on race condition and its value is unpredictable.

May I know whether there are any solution to handle such a case please?

Hi @Tonny_Tc,

If the need is to have a different logic based on whether the multi-instance activity being approved by all or by only some then I recommend to go with something similar to @Niall’s solution

Hi @hassang ,

Thanks a lot for your great advice. I’ve got the idea that the solution works in the case of approved by all (the condition event to check whether a variable set to be false when someone rejects in the user tasks). However, would you please expain something more detail about the case of majority pass (maybe 60% approved means approved).

Hi @Tonny_Tc,

Below example might be of help to you

1 Like

Hi @hassang ,

Thanks a lot for your reference again. However, the solution uses a classic read-then-write pattern which may cause race consition on the same variable. Let’s say there are two person just try to complete their user task via REST call or Tasklist at the same time, and then two threads are created to execute to task complete listener. That’s exactly what I’m concerned with – (suppose yesVotes is 0 now) one thread read the yesVotes variable first, and then another thread read the same variable and write back its value plus 1(yesVotes is 1 now), finally the first thread write it back (it is still 1). You can say, in the condition, two person vote YES, but the yesVotes is 1 eventually.

UPDATED:
I’ve written a test to let a thread pool complete some task (nearly) at the same time. Then, a OptimisticLockingException was thrown which said Execution of 'UPDATE VariableInstanceEntity[27747ebd-afda-11ec-8304-9a41ae154892]' failed. Entity was updated by another transaction concurrently. Thus, may I consider that there is no race condition beacause of optimistic lock and what I should do is handle the exception and then let the failed user complete his task again?

Hi @Tonny_Tc,

Camunda uses Optimistic Locking for concurrency control so if completing a task leads to concurrent modification of data then OptimisticLockingException gets thrown.

https://docs.camunda.org/manual/7.16/user-guide/process-engine/transactions-in-processes/#optimistic-locking-in-camunda

Hi @Tonny_Tc,

Another solution came to mind which I did not try.

You can try using a service task (async before is ticked) following the multi-instance approval activity in which you can query historical data using the historyService, and as a result determine # of approves.

1 Like

Hi @hassang ,

Thank you for your great help. I’ve now got the point and will try your solution later.

1 Like

Hi @Tonny_Tc

I had the time to try the 2nd solution.
Kindly find attached a running simplified example in which script task is used.

test-multi-approval.bpmn (7.3 KB)

Below is a snip of the code used to query historical variable instances (assuming “approved” is the local variable name used in the multi-instance task)
execution.getProcessEngineServices().getHistoryService().createHistoricVariableInstanceQuery().processInstanceId(execution.getProcessInstanceId()).variableValueEquals("approved", true).count();

Hi @hassang ,

This helps me great! I found it also works for parallel multi instance call activity, which could collect variables in subprocesses without the out mapping.

Many thanks for your kind and warm help!

1 Like