Hi, in the below process, whilst the parallel multi-instance “approval request” user task is active I want to support the addition of new approvers. The approach (discussed in a separate topic) uses an non-interrupting message catch event in the case that a new approver is added.
The expectation is the message would carry the new approver’s name and this would be saved into a process variable and then used to assign the “additional approval request” task to that person.
My question is about the atomicity of the process variable across the catching event and the next task and risk of another message event overwriting the value before its read.
e.g. events in this sequence, creates two executions (tokens)
t0: message event 1 (write process var “new_approver” = rob)
t1: message event 2 (write process var “new_approver” = sue)
t2: execute “additional approval task” (read process var “new_approver” = sue)
t3: execute “additional approval task” (read process var “new_approver” = sue)
How can I achieve the expected behaviour here without risking concurrency problems? I am using Camunda 7.
I conducted a small experiment and found that one way to prevent overwriting is to pass a local variable alongside the new_approver process variable as part of the message correlation call. This ensures that only the first call succeeds, and any subsequent calls made before the first call completes will fail with the following error message:
{
"type": "OptimisticLockingException",
"message": "ENGINE-03005 Execution of 'INSERT VariableInstanceEntity[9e7e6fdb-408c-11ef-87be-e40d36e80e3c]' failed. Entity was updated by another transaction concurrently.",
"code": 1
}
You can test this using the attached simple process. test_process.bpmn (4.9 KB)
Thanks @hassang for taking the time to do this. I really appreciate all the help I have been getting from the community.
Is this dependent on using a local variable (vs. a process variable)? If so, could you explain why this is the case?
In general, I see that the first message correlation is creating a local variable in a transaction that is not committed until the next wait state (the user task) and hence any other attempt to correlate (and write the same local variable) is under the scope of a separate transaction. The last commit fails with optimistic lock exception - is that right?
In my experiment, I found that this behavior occurs only with local variables. It seems that setting local variables is considered part of the same transaction as the message correlation, whereas setting process variables is not.
Message correlation, including the setting of local variables, is only committed once the execution reaches a waiting state.
Refer to the link below for more information on how concurrency conflict detection works.
Thanks for the link to the docs detailing the concurrency handling. I will try this out myself and reproduce. The docs, as far as I can tell, don’t give any insight as to why the behaviour would be different between a local and process variable write.
Hey @hassang - I was able to re-produce the optimistic locking exception. Interestingly, I was able to force the OLE without defining any variable (local or otherwise) just using a simple correlation on the message and business key. I am using Camunda v7.21.0.
I used your BPMN but changed you busy-loop script task for a java.lang.Thread.sleep() for 10 seconds. Very ad-hoc, but I send 2 correlations in using curl and always get the OLE on the later correlation. This behaviour seems to consistent with what you first suggested.
I wonder if I am doing differently to you or if it’s an engine version difference?
Awesome finding…
I only tested a correlation using message name. No business key value was supplied. I will do a new test supplying a business key value.
@herrier
Correlation with a business key, correlation keys, or both produces the optimistic locking exception. This makes sense as a correlation key is supposed to be provided in such cases so there is no place for concurrency problems.