Hi @thorben,
i finally was able to reproduce the behaviour in a simple process model. I assume that the bug is correlated to having a (boundary) timer event in one of the paths.
I’ll attach the bpmn and my modified test. Will that be ok for you or do you need the test within the unit test template you sent me ? I’m asking because I am already way out schedule for the actual feature I have to deliver and will probably need some more time to figure out how to work around this issue
.
I sysout some infos - Activity Instance History ordered by start time descending, Pending Jobs, Current Activity Tree - in the test that illustrate the behaviour:
---------------- Activity History ----------------
HistoricActivityInstanceEntity[activityId=InclusiveGateway_0z98nld, activityName=null, activityType=inclusiveGateway, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=0, startTime=Tue Jul 26 00:00:00 CEST 2016, endTime=Tue Jul 26 00:00:00 CEST 2016, eventType=null, executionId=16, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=timerEvent, activityName=null, activityType=boundaryTimer, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=0, startTime=Tue Jul 26 00:00:00 CEST 2016, endTime=Tue Jul 26 00:00:00 CEST 2016, eventType=null, executionId=16, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=Task2, activityName=Servicetask 2, activityType=serviceTask, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=0, startTime=Tue Jul 26 00:00:00 CEST 2016, endTime=Tue Jul 26 00:00:00 CEST 2016, eventType=null, executionId=16, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=InclusiveGateway_0z98nld, activityName=null, activityType=inclusiveGateway, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=0, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=15, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=endEvent_4a511870-4843-4885-b606-41cacf1a7c2a, activityName=Ende - Dummy, activityType=noneEndEvent, activityInstanceId=null, activityInstanceState=1, parentActivityInstanceId=19, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=1, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=19, processDefinitionId=dummyProcess:1:9, processInstanceId=19, tenantId=null]
HistoricActivityInstanceEntity[activityId=dummyDelegateTask, activityName=Dummy Delegate, activityType=serviceTask, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=19, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=3, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=19, processDefinitionId=dummyProcess:1:9, processInstanceId=19, tenantId=null]
HistoricActivityInstanceEntity[activityId=userTask1, activityName=Usertask 1, activityType=userTask, activityInstanceId=null, activityInstanceState=2, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=31, taskAssignee=null, durationInMillis=32555132, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Tue Jul 26 00:00:00 CEST 2016, eventType=null, executionId=28, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=ExclusiveGateway_1ub6nng, activityName=null, activityType=exclusiveGateway, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=1, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=16, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=userTask1, activityName=Usertask 1, activityType=userTask, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=25, taskAssignee=null, durationInMillis=63, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=22, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=startEvent_b4e0469b-414e-4d8e-b041-1db19f1b7c12, activityName=Start + Dummy, activityType=startEvent, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=19, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=0, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=19, processDefinitionId=dummyProcess:1:9, processInstanceId=19, tenantId=null]
HistoricActivityInstanceEntity[activityId=subprocess1, activityName=Subprocess1, activityType=callActivity, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=19, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=104, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=17, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=InclusiveGateway_0k66q7u, activityName=null, activityType=inclusiveGateway, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=2, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=11, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
HistoricActivityInstanceEntity[activityId=StartEvent_1, activityName=null, activityType=startEvent, activityInstanceId=null, activityInstanceState=0, parentActivityInstanceId=11, calledProcessInstanceId=null, calledCaseInstanceId=null, taskId=null, taskAssignee=null, durationInMillis=2, startTime=Mon Jul 25 14:57:24 CEST 2016, endTime=Mon Jul 25 14:57:24 CEST 2016, eventType=null, executionId=11, processDefinitionId=ProcessWithParallelGateway:1:3, processInstanceId=11, tenantId=null]
---------------- Pending Jobs ----------------
MessageEntity[repeatnull, id=35, revision=1, duedate=null, lockOwner=null, lockExpirationTime=null, executionId=15, processInstanceId=11, isExclusive=true, retries=3, jobHandlerType=async-continuation, jobHandlerConfiguration=transition-create-scope, exceptionByteArray=null, exceptionByteArrayId=null, exceptionMessage=null, deploymentId=1]
MessageEntity[repeatnull, id=40, revision=1, duedate=null, lockOwner=null, lockExpirationTime=null, executionId=16, processInstanceId=11, isExclusive=true, retries=3, jobHandlerType=async-continuation, jobHandlerConfiguration=transition-create-scope, exceptionByteArray=null, exceptionByteArrayId=null, exceptionMessage=null, deploymentId=1]
----------------------------------------------
---------------- Activity Instance Tree ----------------
└── ProcessWithParallelGateway:1:3=>11
├── transition to/from Task3:15
└── transition to/from Task3:16
When I remove the boundary timer event the gateway is just triggered once
ProcessWithParallelGateway.bpmn (13.4 KB)
package de.vorsorge.prozess.test;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.camunda.bpm.engine.ManagementService;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.camunda.bpm.engine.impl.util.ClockUtil;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.DeploymentBuilder;
import org.camunda.bpm.engine.runtime.Execution;
import org.camunda.bpm.engine.runtime.Job;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.google.common.collect.Maps;
import de.vorsorge.theo.prozess.model.Prozess;
import de.vorsorge.theo.util.Tag;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class InclusiveGatewayProzessTest {
private static final String DUMMY_DELEGATE_TASK_ID = "dummyDelegateTask";
private static final String TASK3_ACTIVITY_ID = "Task3";
private static final String TASK2_ACTIVITY_ID = "Task2";
@Configuration
@Import(value={ProzessTestConfig.class})
static class Config{
@Bean
public InclusiveGatewayProcessDelegate inclusiveGatewayProcessDelegate(){
return new InclusiveGatewayProcessDelegate();
}
}
@Autowired
private ProcessEngine engine;
@Before
public void setUp() {
deploy("ProcessWithParallelGateway.bpmn");
mockSubProzess("dummyProcess", DummyDelegate.class);
}
@Test
public void test(){
HashMap<String, Object> variables = Maps.newHashMap();
variables.put("timerDate", tomorrow());
ProcessInstance processInstance = engine.getRuntimeService().startProcessInstanceByKey("ProcessWithParallelGateway", variables);
submitUserTask1();
executeAsyncTask(DUMMY_DELEGATE_TASK_ID);
triggerTimerEvent();
executeAsyncTask(TASK2_ACTIVITY_ID);
printActivityHistory();
printActiveJobs();
printActivityInstanceTree(processInstance);
executeAsyncTask(TASK3_ACTIVITY_ID);
int runningInstances = engine.getRuntimeService().createProcessInstanceQuery().processDefinitionKey("ProcessWithParallelGateway").list().size();
assertThat(runningInstances, is(0));
assertThat(activityInstanceCount(TASK3_ACTIVITY_ID), is(1));
}
public void printActivityInstanceTree(ProcessInstance processInstance) {
System.out.println("---------------- Activity Instance Tree ----------------");
System.out.println(engine.getRuntimeService().getActivityInstance(processInstance.getId()));
System.out.println("----------------------------------------------------");
}
public void printActiveJobs() {
System.out.println("---------------- Pending Jobs ----------------");
engine.getManagementService().createJobQuery().active().list()
.stream()
.forEach(job -> System.out.println(job.toString()));
System.out.println("----------------------------------------------");
}
public void printActivityHistory() {
System.out.println("---------------- Activity History ----------------");
engine.getHistoryService().createHistoricActivityInstanceQuery().orderByHistoricActivityInstanceStartTime().desc().list()
.stream()
.forEach(activityInstance -> System.out.println(activityInstance.toString()));
System.out.println("--------------------------------------------------");
}
private void triggerTimerEvent() {
ClockUtil.setCurrentTime(tomorrow());
executeAsyncTask("timerEvent");
}
private Date tomorrow() {
return Date.from(LocalDate.now().plusDays(1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
}
private void submitUserTask1() {
HashMap<String, Object> variables = Maps.newHashMap();
variables.put("abbrechen", false);
engine.getFormService().submitTaskForm(engine.getTaskService().createTaskQuery().executionId(executionIdFor("userTask1")).singleResult().getId(), variables);
}
private String executionIdFor(String activityId) {
String executionId = engine.getRuntimeService().createExecutionQuery().activityId(activityId).singleResult().getId();
return executionId;
}
private int activityInstanceCount(String activityId){
return engine.getHistoryService().createHistoricActivityInstanceQuery().activityId(activityId).list().size();
}
private void executeAsyncTask(String activityId){
ManagementService managementService = engine.getManagementService();
List<Job> jobs = managementService.createJobQuery().active().activityId(activityId).list();
assertThat(jobs.size(), is(1));
managementService.executeJob(jobs.get(0).getId());
}
private void deploy(String... resources) {
DeploymentBuilder deploymentBuilder = engine.getRepositoryService().createDeployment();
for (String resource: resources) {
deploymentBuilder.addClasspathResource(resource);
}
deploymentBuilder.deploy();
}
public void mockSubProzess(String key, Class<?> dummyDelegate) {
String name = "Dummy";
BpmnModelInstance modelInstance = Bpmn
.createExecutableProcess(key).name(name)
.startEvent().name("Start + "+name).serviceTask().id(DUMMY_DELEGATE_TASK_ID)
.name("Dummy Delegate").camundaAsyncBefore()
.camundaClass(dummyDelegate.getName()).endEvent()
.name("Ende - "+name).done();
deployMockProzess(key, modelInstance);
}
public Deployment deployMockProzess(String key, BpmnModelInstance modelInstance) {
/*
* Workaround for https://app.camunda.com/jira/browse/CAM-4787
*/
ByteArrayOutputStream output = new ByteArrayOutputStream();
Bpmn.writeModelToStream(output , modelInstance);
return engine.getRepositoryService().createDeployment()
.addInputStream(key + ".bpmn", new ByteArrayInputStream(output.toByteArray())).deploy();
}
public static final class DummyDelegate implements JavaDelegate{
@Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println(this.getClass().getSimpleName());
}
}
}