External Task to execute one Task at a time

We have been using External Task in our flow for a quite time. we are looking to execute tasks continously, but before executing 2nd task, we have to make sure 1st task is completed inside External Task. In a nutshell: if my 1st task is taking sometime to complete inside external task, then the second task shouldn’t reach external task.

As you can see, there are 1.4k tasks stuck in my external Service task, and each task inside External Service Task, takes 30s to execute, and only if one task is completed the second task should reach my external task.
Here is my code snippet:
ExternalTaskClient client = ExternalTaskClient.create().baseUrl(“http://” +
PROCESS_ENGINE_URL + “/engine-rest”).disableBackoffStrategy().maxTasks(1).workerId(“eventWorker”).build();
TopicSubscriptionBuilder sporadicEventStatusUpdate = client.subscribe(“sporadicMonitoring”).handler((externalTask, externalTaskService) → {
Map<String, Object> allVariables = null;
try {
allVariables = postProcessingService.sporadicMonitoring(externalTask);
} catch (IOException e) {
} catch (ParseException e) {
externalTaskService.complete(externalTask, allVariables);

So, what exactly is the problem? Based on your description, if you’re only completing one external task at a time, I would fully expect a backlog of external tasks to build up if they’re running through the first portion of your process faster than the single task can be completed. You’ve essentially designed in a bottleneck…

Hi @jgigliotti,
I get your point here @jgigliotti, there would be backlog of external task, ready to get executed, and I guess that would bring some delay, totally Agreed!
I have one more query @jgigliotti, Suppose if i am making a api call through my external task, and the response was not successful, then my task keeps on calling the api because of the error, until it is successful. Is there any way to complete an external task when there is a error within the external task?

It would be up to you to catch that exception in your external task code, that way you can handle it however you see fit. There may be some cases where you complete the task anyway (maybe with a process variable indicating what the error was?). I would also suggest looking at whether or not you want to create an incident as an alternative to outright failing or completing successfully.

HI @jgigliotti,

If at all I don’t execute one task at a time Synchronously, I am facing OtimisticLockingException, since the entity is getting updated two concurrent transactions, How can i avoid OptimisticLockingException, when two transacions are getting executed concurrently. Also if there is a dailure in external task, how can i avoid retries, and complete external task.

Take a look at the recommendations in the docs. You have a few different things to tweak. It looks like the 30s execution time may put you in the maxTasks=1 recommendation at which point you’ll want to to ramp up multiple external clients. I think you could also take a look at extending your lock timeout.

What kinda of failure are we talking about? If you’re talking about inside your external task code, the easiest thing to do is structure your code in such a way where you can catch the exceptions you want to to handle and complete the task instead of letting that exception bubble up.

Hi @jgigliotti,
If the exception is occurring at externalTaskService.complete(externalTask, allVariables);how will i be able to complete the task, currently I am getting exceptions in two cases:

  1. org.camunda.bpm.engine.OptimisticLockingException: ENGINE-03005 Execution of 'UPDATE VariableInstanceEntity[f2e33347-a9fc-11ea-8980-4e41604cc5e4]' failed. Entity was updated by another transaction concurrently.at org.camunda.bpm.engine.impl.db.EnginePersistenceLogger.concurrentUpdateDbEntityException(EnginePersistenceLogger.java:134) at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.handleOptimisticLockingException(DbEntityManager.java:498) at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.checkFlushResults(DbEntityManager.java:450) at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flushDbOperations(DbEntityManager.java:366) at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flushDbOperationManager(DbEntityManager.java:324) at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flush(DbEntityManager.java:296) at org.camunda.bpm.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:207) at org.camunda.bpm.engine.impl.interceptor.CommandContext.close(CommandContext.java:136)at org.camunda.bpm.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:115) at org.camunda.bpm.engine.impl.interceptor.ProcessApplicationContextInterceptor.execute(ProcessApplicationContextInterceptor.java:69) at org.camunda.bpm.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:32) atorg.camunda.bpm.engine.impl.MessageCorrelationBuilderImpl.execute(MessageCorrelationBuilderImpl.java:266)at org.camunda.bpm.engine.impl.MessageCorrelationBuilderImpl.correlateWithResult(MessageCorrelationBuilderImpl.java:210)at org.camunda.bpm.engine.impl.MessageCorrelationBuilderImpl.correlate(MessageCorrelationBuilderImpl.java:202)

  2. 2020-07-31 01:13:07.550 ERROR 45 --- [criptionManager] org.camunda.bpm.client : TASK/CLIENT-03004 Exception on external task service method invocation for topic 'generateNotification': 2020-07-31 01:13:06.995 INFO 45 --- [criptionManager] c.h.b.E.S.EventNotificationService : The External Task(Event Configuration) fd76a88c-d2ca-11ea-97cb-322f61d443b4 has been completed! For CPP-CPP_Output_Deviation org.camunda.bpm.client.exception.NotResumedException: TASK/CLIENT-01009 Exception while completing the external task: The corresponding process instance could not be resumed. Reason: status code: 500, reason phrase: {"type":"OptimisticLockingException","message":"ENGINE-03005 Execution of 'UPDATE VariableInstanceEntity[576dca95-ccc8-11ea-97cb-322f61d443b4]' failed. Entity was updated by another transaction concurrently."} at org.camunda.bpm.client.impl.ExternalTaskClientLogger.externalTaskServiceException(ExternalTaskClientLogger.java:124) ~[camunda-external-task-client-1.3.0.jar!/:1.3.0] at org.camunda.bpm.client.task.impl.ExternalTaskServiceImpl.complete(ExternalTaskServiceImpl.java:64) ~[camunda-external-task-client-1.3.0.jar!/:1.3.0] at org.camunda.bpm.client.task.impl.ExternalTaskServiceImpl.complete(ExternalTaskServiceImpl.java:56) ~[camunda-external-task-client-1.3.0.jar!/:1.3.0] at com.hv.bmc.EventNotificationApplication.Services.EventNotificationService.lambda$eventGenerationController$2(EventNotificationService.java:421) ~[classes!/:na] at org.camunda.bpm.client.topic.impl.TopicSubscriptionManager.handleExternalTask(TopicSubscriptionManager.java:152) [camunda-external-task-client-1.3.0.jar!/:1.3.0] at org.camunda.bpm.client.topic.impl.TopicSubscriptionManager.lambda$acquire$0(TopicSubscriptionManager.java:108) [camunda-external-task-client-1.3.0.jar!/:1.3.0] at java.util.Arrays$ArrayList.forEach(Arrays.java:3880) ~[na:1.8.0_201] at org.camunda.bpm.client.topic.impl.TopicSubscriptionManager.acquire(TopicSubscriptionManager.java:103) [camunda-external-task-client-1.3.0.jar!/:1.3.0] at org.camunda.bpm.client.topic.impl.TopicSubscriptionManager.run(TopicSubscriptionManager.java:87) [camunda-external-task-client-1.3.0.jar!/:1.3.0] at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_201]

If you observe second exception very closely, it is unable to complete the external task, EventNotificationService.java:421 at this line, the code is, externalService.complete(externalTask, ProcessVariables);

Ah, that’s a little bit tougher. It’s unclear based on the information provided why there are multiple updates of the same variables. If you increase the lock timeout (try something really high like 2 min, to make sure tasks are finishing before the lock expires), do the exceptions go away? When you were at maxTasks(1) did you have any OptimisticLocking exceptions?

There isn’t much you can do for an exception this high in the chain. You have to be able to successfully complete the task, throw an error, or generate an incident, otherwise the engine will never know what happened to the task.