cancel
Showing results for 
Search instead for 
Did you mean: 

User tasks completed concurrently in different threads

jellybean
Champ in-the-making
Champ in-the-making
I am using Activiti 5.9.

I tried running a process with parallel gateway and two user tasks an each path.   One of the user tasks is a non-sequential multi-instance.  Then I complete each of the user tasks in a separate thread.  Occasionally, I am getting the ActivitiOptimisticLockingException when calling TaskService.complete(taskId).  Is this expected behavior or a bug?  Does this mean one should not use the parallel gateway for user tasks because it is totally possible for two different users to complete these user tasks at the same time? Thank you for your time.

This is the process definition.
<process id="testUserTask" name="Test User Task">
    <startEvent id="startevent1" name="Start"></startEvent>
    <parallelGateway id="parallelgateway1" name="Parallel Gateway"></parallelGateway>
    <userTask id="usertask1" name="User Task 1" activiti:async="true" activiti:candidateUsers="rocket">
      <multiInstanceLoopCharacteristics isSequential="false">
        <loopCardinality>3</loopCardinality>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <userTask id="usertask2" name="User Task 2" activiti:async="true" activiti:candidateUsers="rocket"></userTask>
    <parallelGateway id="parallelgateway2" name="Parallel Gateway"></parallelGateway>
    <scriptTask id="scripttask1" name="Script Task" activiti:async="true" scriptFormat="groovy">
      <script><![CDATA[sleep(4000)]]></script>
    </scriptTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="parallelgateway1"></sequenceFlow>
    <sequenceFlow id="flow2" name="" sourceRef="parallelgateway1" targetRef="usertask1"></sequenceFlow>
    <sequenceFlow id="flow3" name="" sourceRef="parallelgateway1" targetRef="usertask2"></sequenceFlow>
    <sequenceFlow id="flow4" name="" sourceRef="usertask1" targetRef="parallelgateway2"></sequenceFlow>
    <sequenceFlow id="flow5" name="" sourceRef="usertask2" targetRef="parallelgateway2"></sequenceFlow>
    <sequenceFlow id="flow6" name="" sourceRef="parallelgateway2" targetRef="scripttask1"></sequenceFlow>
    <sequenceFlow id="flow7" name="" sourceRef="scripttask1" targetRef="endevent1"></sequenceFlow>
  </process>

This is the exception stack trace.
org.activiti.engine.ActivitiOptimisticLockingException: VariableInstanceEntity[3716] was updated by another transaction concurrently
   at org.activiti.engine.impl.db.DbSqlSession.flushUpdates(DbSqlSession.java:452)
   at org.activiti.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:348)
   at org.activiti.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:149)
   at org.activiti.engine.impl.interceptor.CommandContext.close(CommandContext.java:105)
   at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:49)
   at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:33)
   at org.activiti.engine.impl.TaskServiceImpl.complete(TaskServiceImpl.java:144)
   at test.base.HomeFactory.completeTask(HomeFactory.java:52)
   at test.base.MyWorkerThread.run(MyWorkerThread.java:31)
   at java.lang.Thread.run(Thread.java:662)
2 REPLIES 2

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
This behaviour can occur, is expected and not a bug. Just complete the second task again and it will succeed. No need to skip using this gateway…

jellybean
Champ in-the-making
Champ in-the-making
Thank you. This really helps.

The solution to retry completing the user tasks make me wonder why can't a similar approach be implemented in Activiti when trying to join (parallel gateway) non-exclusive service tasks running concurrently. I created a similar process where there are 3 async service tasks with "exclusive=false" following a parallel gateway.  As expected, I got the Optimistic Locking Exception.  Going forward, is Activiti going to build into the engine the retry mechanism at the join of the parallel gateway in a way that it only retry the transition, but not the entire transaction?