Standalone External Task Service - java Parse Error

Hello, I’m working on a POC deployment architecture for handling what will end up being lots of long running external tasks. My hope was to create a generic java service that I could configure to lock and complete various topics, solely for use with external tasks – my camunda process engine and executor are within a webapp tier elsewhere.

I am able to poll and lock the topics I’m interested in, however when I want to take any action on the task, complete, handleFailure, or unlock, I am met with this NPE parsing error:

12:21:03.545 [main] ERROR org.camunda.bpm.engine.context - ENGINE-16004 Exception while closing command context: ENGINE-01009 Error while parsing process
org.camunda.bpm.engine.ProcessEngineException: ENGINE-01009 Error while parsing process
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseLogger.parsingProcessException(BpmnParseLogger.java:46) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParse.execute(BpmnParse.java:258) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.deployer.BpmnDeployer.transformDefinitions(BpmnDeployer.java:101) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.AbstractDefinitionDeployer.transformResource(AbstractDefinitionDeployer.java:96) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.AbstractDefinitionDeployer.parseDefinitionResources(AbstractDefinitionDeployer.java:71) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.AbstractDefinitionDeployer.deploy(AbstractDefinitionDeployer.java:61) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.deploy.cache.CacheDeployer$2.call(CacheDeployer.java:62) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.deploy.cache.CacheDeployer$2.call(CacheDeployer.java:59) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.interceptor.CommandContext.runWithoutAuthorization(CommandContext.java:473) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.deploy.cache.CacheDeployer.deployOnlyGivenResourcesOfDeployment(CacheDeployer.java:59) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.deploy.cache.ResourceDefinitionCache.resolveDefinition(ResourceDefinitionCache.java:109) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.deploy.cache.ResourceDefinitionCache.findDeployedDefinitionById(ResourceDefinitionCache.java:52) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.deploy.cache.DeploymentCache.findDeployedProcessDefinitionById(DeploymentCache.java:73) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.ensureProcessDefinitionInitialized(ExecutionEntity.java:752) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.getProcessDefinition(ExecutionEntity.java:734) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.cfg.auth.AuthorizationCommandChecker.checkUpdateProcessInstance(AuthorizationCommandChecker.java:184) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.cfg.auth.AuthorizationCommandChecker.checkUpdateProcessInstanceById(AuthorizationCommandChecker.java:178) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.cmd.HandleExternalTaskCmd.execute(HandleExternalTaskCmd.java:55) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.cmd.HandleExternalTaskCmd.execute(HandleExternalTaskCmd.java:30) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.interceptor.CommandExecutorImpl.execute(CommandExecutorImpl.java:24) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:104) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.interceptor.ProcessApplicationContextInterceptor.execute(ProcessApplicationContextInterceptor.java:66) [camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30) [camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.ExternalTaskServiceImpl.handleFailure(ExternalTaskServiceImpl.java:55) [camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.ExternalTaskServiceImpl.handleFailure(ExternalTaskServiceImpl.java:51) [camunda-engine-7.7.0.jar:7.7.0]
	at io.insurdata.workflow.ext.ExternalWorker.work(ExternalWorker.java:61) [classes/:na]
	at io.insurdata.workflow.ext.ExternalWorkerMain.doMain(ExternalWorkerMain.java:39) [classes/:na]
	at io.insurdata.workflow.ext.ExternalWorkerMain.main(ExternalWorkerMain.java:13) [classes/:na]
Caused by: java.lang.NullPointerException: null
	at org.camunda.bpm.engine.impl.history.parser.HistoryParseListener.addActivityHandlers(HistoryParseListener.java:233) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.history.parser.HistoryParseListener.parseStartEvent(HistoryParseListener.java:142) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParse.parseStartEvents(BpmnParse.java:858) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParse.parseScope(BpmnParse.java:636) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParse.parseProcess(BpmnParse.java:545) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParse.parseProcessDefinitions(BpmnParse.java:479) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParse.parseRootElement(BpmnParse.java:283) ~[camunda-engine-7.7.0.jar:7.7.0]
	at org.camunda.bpm.engine.impl.bpmn.parser.BpmnParse.execute(BpmnParse.java:248) ~[camunda-engine-7.7.0.jar:7.7.0]
	... 26 common frames omitted

It’s just a guess, but I’m wondering if this has to do with my instantiating a full ProcessEngine and then getting the ExternalTaskService from it…it looks like the error is resulting from trying to parse a bpmn process file that will not exist on this server (it’s in a war on the webapp). Is there a way for me overcome this without the need for parsing and just have essentially a standalone ExternalTaskService, e.g. get task, complete task, report task ? Below is, simplistically, all that the executable does:

public static void doMain() throws Exception {
        ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration()
                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE)
                .setJdbcDriver(config.getJdbcDriver())
                .setJdbcUrl(config.getJdbcUrl())
                .setJdbcUsername(config.getJdbcUser())
                .setJdbcPassword(config.getJdbcPassword())
                .setHistory("auto")
                .setJobExecutorActivate(false)
                .buildProcessEngine();

        ExternalTaskService externalTaskService = processEngine.getExternalTaskService();

        logger.info("Building external task query...");
        ExternalTaskQueryBuilder builder = externalTaskService.fetchAndLock(1, workerId);
        for (String topic : config.getTopics()) {
            logger.info("Subscribing to external task topic {} at lock interval {}", topic, lockInterval);
            builder.topic(topic, lockInterval);
        }

        while (true) {
            List<LockedExternalTask> tasks = builder.execute();

            for (LockedExternalTask task : tasks) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Got topic {}, task {}", task.getTopicName(), task.getId());
                }

                try {
                    // Do work on task...
                    externalTaskService.complete(task.getId(), workerId); // Error is thrown HERE
                } catch (Exception e) {
                    logger.error("Failed to complete task {}", task.getId(), e);
                    externalTaskService.handleFailure(task.getId(), workerId, e.getMessage(), 0, lockInterval); // Or thrown HERE
                }
                
            }

            Thread.sleep(config.getPollInterval());
        }
}

Nevermind. The issue was simple and unrelated to parsing. The solution was to change in the ProcessEngineConfiguration:

From:

 .setHistory("auto")

To:

.setHistory(ProcessEngineConfiguration.HISTORY_FULL)
1 Like