Tijs, thanks for replying. I'm not running the subprocess sequentially, but rather as a non-sequential exclusive. I need for the external service requests to be sent out all at once and then resume the corresponding execution once the external processing is complete. My understanding, based on the parallel gateway description in your book and a few forum posts I read on the subject, is that with exclusive execution there is a single thread performing a depth first search to find a non-wait (or coming out of wait) branch to run. In a sense, it's a form of queuing to a single processing thread, which makes a lot of sense to avoid synchronization issues and performance impact from synchronization. So if the main processing thread is the "consumer" of this "queuing" then a "producer" would be any thread signaling an execution in a wait state to resume by calling RuntimeService.signal(executionId). So while my subprocess instances are executing "in parallel" meaning that any one of them can be told to resume at any time, any non-wait portion of each instance is still executing sequentially by a single main processing thread.
So again, in my understanding, unless the job executor is running multiple threads, which it shouldn't unless there are explicit asynchronous non-exclusive tasks (not a good idea in my opinion - I wonder why this is even allowed), I shouldn't be seeing any concurrent modification of any data. What I'm seeing is that an ActivitiOptimisticLockingException is thrown to a "producer" thread when it tries to mark an instance of the subprocess to be picked up next time the main processing thread gets a chance to run it.
Thanks for your help!
Here's the exception I'm getting:
org.activiti.engine.ActivitiOptimisticLockingException: ByteArrayEntity[id=220, name=var-testCases, size=693] was updated by another transaction concurrently
at org.activiti.engine.impl.db.DbSqlSession.flushUpdates(DbSqlSession.java:620)
at org.activiti.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:502)
at org.activiti.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:175)
at org.activiti.engine.impl.interceptor.CommandContext.close(CommandContext.java:122)
at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:66)
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.RuntimeServiceImpl.signal(RuntimeServiceImpl.java:214)
at com.huawei.rndtools.wise.ebuswebsandbox.DemoServer$1.run(DemoServer.java:87)
at java.lang.Thread.run(Thread.java:744)
Here is the subprocess definition:
<subProcess id="subprocess1" name="Sub Process">
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="gtrList" activiti:elementVariable="gtr"></multiInstanceLoopCharacteristics>
<startEvent id="startevent2" name="Start"></startEvent>
<sequenceFlow id="flow23" sourceRef="startevent2" targetRef="servicetask6"></sequenceFlow>
<serviceTask id="servicetask6" name="Run Test Case" activiti:class="com.huawei.rndtools.wise.designersandbox.demo.services.RunTestCaseService">
<extensionElements>
<activiti:executionListener event="end" class="com.huawei.rndtools.wise.useragent.ActivitiEngineImpl"></activiti:executionListener>
</extensionElements>
</serviceTask>
<sequenceFlow id="flow24" sourceRef="servicetask6" targetRef="receivetask1"></sequenceFlow>
<receiveTask id="receivetask1" name="Wait for completion"></receiveTask>
<sequenceFlow id="flow25" sourceRef="receivetask1" targetRef="servicetask7"></sequenceFlow>
<exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
<sequenceFlow id="flow26" sourceRef="servicetask7" targetRef="exclusivegateway1"></sequenceFlow>
<sequenceFlow id="flow27" sourceRef="exclusivegateway1" targetRef="servicetask6">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!testCases.isEmpty()}]]></conditionExpression>
</sequenceFlow>
<serviceTask id="servicetask7" name="Process Test Case Completion" activiti:class="com.huawei.rndtools.wise.designersandbox.demo.services.ProcessTestCaseCompletionService">
<extensionElements>
<activiti:executionListener event="end" class="com.huawei.rndtools.wise.useragent.ActivitiEngineImpl"></activiti:executionListener>
</extensionElements>
</serviceTask>
<endEvent id="endevent2" name="End"></endEvent>
<sequenceFlow id="flow28" sourceRef="exclusivegateway1" targetRef="endevent2">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${testCases.isEmpty()}]]></conditionExpression>
</sequenceFlow>
</subProcess>