AnsweredAssumed Answered

How to handle or avoid an optimistic locking exception

Question asked by schmke on Mar 17, 2017
Latest reply on Nov 29, 2017 by haridaniel

I have an interesting scenario using 5.21 (moving to 5.22 and perhaps 6 soon) where I'm getting an ActivitiOptimisticLockingException. I'd like to figure out the best way to handle it or avoid it entirely.

 

I have a process that has a user task that on completion has Java service task that calls an API. The process then continues on to an end step. Pretty simple.

 

However, as a result of the API call, several other instances of the same process may be invalidated and I want to remove them. This gets triggered by the server the API call is made to sending out a JMS message, and the processing of the message looking up the related process instances by a specific variable/value. Presently, the process instance being completed shows up as a related process too (it has the same variable/value as the others).

 

This message and processing is all asynchronous to the process instance completion and happens quickly enough that the message processing tries to delete the process instance that the user completed the task for before the engine has fully finished the completion, and I get an ActivitiOptimisticLockingException, usually on the thread completing the task. Specifically:

 

org.activiti.engine.ActivitiOptimisticLockingException: HistoricVariableInstanceEntity[id=2647, name=euid2, revision=0, type=string, textValue=1000002002] was updated by another transaction concurrently
at org.activiti.engine.impl.db.DbSqlSession.flushUpdates(DbSqlSession.java:880)
at org.activiti.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:619)
at org.activiti.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:212)
at org.activiti.engine.impl.interceptor.CommandContext.close(CommandContext.java:138)
at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:66)
at org.activiti.engine.impl.interceptor.JtaTransactionInterceptor.execute(JtaTransactionInterceptor.java:65)
at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:31)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:40)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:35)
at org.activiti.engine.impl.FormServiceImpl.submitTaskFormData(FormServiceImpl.java:70)

 

Now, this occurs late enough in the task completion that the task itself is actually completed, so I suspect it is just historical variables that may not be fully populated correctly, but I'd still like to avoid it happening.

 

So, is there any way to avoid a simultaneous process instance deletion from affecting the processing of the same process instance being completed? Does 5.22 have anything to help with this? Will version 6 change this behavior at all? Or do I need to build something into my process to detect and avoid this? Or are there any engine settings that would alter this behavior?

 

One thought I had was in the message processing doing the delete, to look for any tasks for the process instance and if there are none, that would indicate the process instance is the one we want to let complete. The others we want to delete would still be at the user task.

 

Or do I need to set a process variable before the API call in the process that identifies that process instance as the one to not delete and use it when looking up the related process instances?

 

Thanks for any insight or suggestions.

Outcomes