I recently ran into a issue where two users completed one task at same time. Process after this task is rather complex, including parallel gateways and call activities, where some data are updated in external system, so it runs for 20-30 seconds.
Problem is that when two users completed this task within 5 seconds, one failed due to data inconsistency in external system (which is expected), but also the first one failed with OptimisticLockingException
org.activiti.engine.ActivitiOptimisticLockingException: TaskEntity[13195361] was updated by another transaction concurrently at org.activiti.engine.impl.db.DbSqlSession$DeletePersistentObjectOperation.execute(DbSqlSession.java:238) at org.activiti.engine.impl.db.DbSqlSession.flushDeletes(DbSqlSession.java:667) at org.activiti.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:461) at org.activiti.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:167) at org.activiti.engine.impl.interceptor.CommandContext.close(CommandContext.java:114)
This is on Activiti 5.11 on Oracle.
I would expect that first execution would survive correctly. I don't know whether it is more db or activiti issue and only idea I have is to create some locking mechanism in application that would block such calls or claim task for individual user before calling task complete, but since the users are not used to claiming task I could get into problems when complete fails and task got stuck on individual user.
Hmm your assumption is correct: one should get the optimistic locking exception, the other should just execute.
20-30 secs does sound long for keeping one transaction open. Especially oracle (at least in the past) is known for not coping with that well. So maybe it's an oracle configuration setting? Unless it's a bug, Activiti should execute the way you describe.
you can set task assignee before completing the task and always check if task assignee is not null before completing the task
* assuming you are not maintaining task assignee. if not you need to change taskAssignee to some other value with which you can determine that the task is under processing.