diff --git a/spring-boot/src/main/java/io/vanillabp/camunda7/Camunda7AdapterConfiguration.java b/spring-boot/src/main/java/io/vanillabp/camunda7/Camunda7AdapterConfiguration.java index 930ad56..d53f265 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda7/Camunda7AdapterConfiguration.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda7/Camunda7AdapterConfiguration.java @@ -2,6 +2,7 @@ import io.vanillabp.camunda7.deployment.Camunda7DeploymentAdapter; import io.vanillabp.camunda7.service.Camunda7ProcessService; +import io.vanillabp.camunda7.service.jobs.startprocess.StartProcessJobHandler; import io.vanillabp.camunda7.wiring.Camunda7AdapterProperties; import io.vanillabp.camunda7.wiring.Camunda7TaskWiring; import io.vanillabp.camunda7.wiring.Camunda7TaskWiringPlugin; @@ -28,11 +29,10 @@ import org.springframework.context.annotation.Lazy; import org.springframework.data.repository.CrudRepository; +import javax.annotation.PostConstruct; import java.math.BigInteger; import java.util.function.Function; -import javax.annotation.PostConstruct; - @AutoConfigurationPackage(basePackageClasses = Camunda7AdapterConfiguration.class) @AutoConfigureBefore(CamundaBpmAutoConfiguration.class) @EnableProcessApplication("org.camunda.bpm.spring.boot.starter.SpringBootProcessApplication") @@ -207,5 +207,11 @@ public Camunda7ProcessService newProcessServiceImplementation( return result; } - + + @Bean + public StartProcessJobHandler startProcessJobHandler() { + + return new StartProcessJobHandler(); + } + } diff --git a/spring-boot/src/main/java/io/vanillabp/camunda7/service/Camunda7ProcessService.java b/spring-boot/src/main/java/io/vanillabp/camunda7/service/Camunda7ProcessService.java index 6267bfb..9735f7e 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda7/service/Camunda7ProcessService.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda7/service/Camunda7ProcessService.java @@ -1,10 +1,12 @@ package io.vanillabp.camunda7.service; import io.vanillabp.camunda7.Camunda7AdapterConfiguration; +import io.vanillabp.camunda7.service.jobs.startprocess.StartProcessCommand; import io.vanillabp.springboot.adapter.AdapterAwareProcessService; import io.vanillabp.springboot.adapter.ProcessServiceImplementation; import org.camunda.bpm.engine.ProcessEngine; import org.camunda.bpm.engine.exception.NullValueException; +import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEventPublisher; @@ -51,7 +53,7 @@ public Camunda7ProcessService( this.isNewEntity = isNewEntity; this.getWorkflowAggregateId = getWorkflowAggregateId; this.parseWorkflowAggregateIdFromBusinessKey = parseWorkflowAggregateIdFromBusinessKey; - + } @Override @@ -139,16 +141,20 @@ public DE startWorkflow( .toString(); wakeupJobExecutorOnActivity(); - - processEngine - .getRuntimeService() - .createProcessInstanceByKey(parent.getPrimaryBpmnProcessId()) - .businessKey(id) - .processDefinitionTenantId(parent.getWorkflowModuleId()) - .execute(); - - return workflowAggregateRepository - .save(attachedAggregate); + + // Start workflow asynchronously by Camunda's job-executor + // Hint: this is not done by setting "async-before" on the start-event + // since we don't know which process is used as a call-activity which + // has to be started synchronously. + ((ProcessEngineConfigurationImpl) processEngine + .getProcessEngineConfiguration()) + .getCommandExecutorTxRequired() + .execute(new StartProcessCommand( + parent.getWorkflowModuleId(), + parent.getPrimaryBpmnProcessId(), + id)); + + return attachedAggregate; } diff --git a/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessCommand.java b/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessCommand.java new file mode 100644 index 0000000..0c05ea1 --- /dev/null +++ b/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessCommand.java @@ -0,0 +1,41 @@ +package io.vanillabp.camunda7.service.jobs.startprocess; + +import org.camunda.bpm.engine.impl.interceptor.Command; +import org.camunda.bpm.engine.impl.interceptor.CommandContext; +import org.camunda.bpm.engine.impl.persistence.entity.MessageEntity; + +public class StartProcessCommand implements Command { + + static final String TYPE = "VBP_StartProcess"; + + private final StartProcessJobHandlerConfiguration configuration; + + public StartProcessCommand( + final String workflowModuleId, + final String bpmnProcessId, + final String businessKey) { + + this.configuration = new StartProcessJobHandlerConfiguration( + workflowModuleId, + bpmnProcessId, + businessKey); + + } + + @Override + public String execute( + final CommandContext commandContext) { + + final var entity = new MessageEntity(); + + entity.init(commandContext); + entity.setJobHandlerType(TYPE); + entity.setJobHandlerConfiguration(configuration); + + commandContext.getJobManager().send(entity); + + return entity.getId(); + + } + +} diff --git a/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessJobHandler.java b/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessJobHandler.java new file mode 100644 index 0000000..c15601b --- /dev/null +++ b/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessJobHandler.java @@ -0,0 +1,63 @@ +package io.vanillabp.camunda7.service.jobs.startprocess; + +import org.camunda.bpm.engine.impl.interceptor.CommandContext; +import org.camunda.bpm.engine.impl.jobexecutor.JobHandler; +import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity; +import org.camunda.bpm.engine.impl.persistence.entity.JobEntity; + +import java.util.regex.Pattern; + +public class StartProcessJobHandler implements JobHandler { + + private static final Pattern SPLITTER = Pattern.compile("([^\n]+)\n([^\n]+)\n(.*)"); + + @Override + public String getType() { + return StartProcessCommand.TYPE; + } + + @Override + public void execute( + final StartProcessJobHandlerConfiguration configuration, + final ExecutionEntity execution, + final CommandContext commandContext, + final String tenantId) { + + commandContext + .getProcessEngineConfiguration() + .getProcessEngine() + .getRuntimeService() + .createProcessInstanceByKey(configuration.getBpmnProcessId()) + .businessKey(configuration.getBusinessKey()) + .processDefinitionTenantId(configuration.getWorkflowModuleId()) + .execute(); + + } + + @Override + public StartProcessJobHandlerConfiguration newConfiguration( + final String canonicalString) { + + if (canonicalString == null) { + return null; + } + + final var splitter = SPLITTER.matcher(canonicalString); + if (!splitter.matches()) { + return null; + } + + return new StartProcessJobHandlerConfiguration( + splitter.group(1), + splitter.group(2), + splitter.group(3)); + + } + + @Override + public void onDelete( + final StartProcessJobHandlerConfiguration configuration, + final JobEntity jobEntity) { + // nothing to do + } +} diff --git a/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessJobHandlerConfiguration.java b/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessJobHandlerConfiguration.java new file mode 100644 index 0000000..3022a68 --- /dev/null +++ b/spring-boot/src/main/java/io/vanillabp/camunda7/service/jobs/startprocess/StartProcessJobHandlerConfiguration.java @@ -0,0 +1,43 @@ +package io.vanillabp.camunda7.service.jobs.startprocess; + +import org.camunda.bpm.engine.impl.jobexecutor.JobHandlerConfiguration; + +public class StartProcessJobHandlerConfiguration implements JobHandlerConfiguration { + + private final String businessKey; + + private final String workflowModuleId; + + private final String bpmnProcessId; + + public StartProcessJobHandlerConfiguration( + final String workflowModuleId, + final String bpmnProcessId, + final String businessKey) { + + this.businessKey = businessKey; + this.workflowModuleId = workflowModuleId; + this.bpmnProcessId = bpmnProcessId; + + } + + @Override + public String toCanonicalString() { + + return workflowModuleId + "\n" + bpmnProcessId + "\n" + businessKey; + + } + + public String getWorkflowModuleId() { + return workflowModuleId; + } + + public String getBpmnProcessId() { + return bpmnProcessId; + } + + public String getBusinessKey() { + return businessKey; + } + +} diff --git a/spring-boot/src/main/java/io/vanillabp/camunda7/wiring/TaskWiringBpmnParseListener.java b/spring-boot/src/main/java/io/vanillabp/camunda7/wiring/TaskWiringBpmnParseListener.java index 338c9c3..ea07461 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda7/wiring/TaskWiringBpmnParseListener.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda7/wiring/TaskWiringBpmnParseListener.java @@ -465,12 +465,20 @@ private void resetAsyncBeforeAndAsyncAfter( @Override public void parseStartEvent( - final Element element, + final Element startElement, final ScopeImpl scope, final ActivityImpl activity) { - - resetAsyncBeforeAndAsyncAfter(element, activity, Async.SET_ASYNC_BEFORE_ONLY); - + + final var isEventBasedStartEvent = startElement.element("messageEventDefinition") != null; + if (isEventBasedStartEvent) { + resetAsyncBeforeAndAsyncAfter(startElement, activity, Async.SET_ASYNC_BEFORE_ONLY); + } else { + // plain start events need to be handled synchronously in cases of call-activities. + // in cases of starting an independent process the Camunda7ProcessService is + // responsible for running this asynchronously. + removeAsyncBeforeAndAsyncAfter(startElement, activity); + } + } @Override