This blog discusses a number of ways to write workflows that integrate with an external application asynchronously. In particular, how to handle the case when you need to wait for the external application to return for an unknown and varied period.
Receive Task
The BPMN standard has defined a Receive Task to manage an asynchronous business process. For example if a mortgage application includes a user identification verification, that part may be managed outside of the workflow and the workflow should wait at at Receive Task until the verification is complete and an external system triggers the Receive Task to move on. Configuration of a Receive Task is pretty straight forward, you just define the task name, an example is shown below:
The task can then be signalled to complete by determining its execution ID and using the Runtime Service to trigger the task. In the example above you can also pass in variables with that can be used to determine the outcome of the business process (verification) that was completed. ex = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).activityId(“verifyIDTask”).singleResult(); System.out.println(“Execution ID: ” + ex.getId() + ” activityID:” + ex.getActivityId()); assertEquals(“generateIDTask”,ex.getActivityId()); assertNotNull(ex); runtimeService.trigger(ex.getId(), this.variables);
Triggerable
In our case we did not have a long running background business process we were waiting on but instead we were calling out to an external application to do some processing and expected a result in less than a second or up to an hour depending on the external system we were calling. For this use case we decided on a Service Task that has been set asynchronous and triggerable. This means that when the service task is reached it will be added to a job queue by flowable and run by the job service (see this blog for an excellent explanation on the asynchronous flag). The task listener class that executed with the class then called the external app via an ESB and finished. The ESB simply acknowledged that it has successfully received the request. Although the executor for the service task completes, the Service Task will wait for a trigger before it completes and moves to its outbound flow. The diagram below shows the setup of the Async Triggerable Service Task.
Triggering the Task to complete
You can trigger the task to complete a number of ways. From the external Application you can use a Rest request to trigger the Task:
- Get the execution id using the GET method of –> http://<IP:PORT>/app-rest/service/runtime/executions/. Get the correct execution id.
- Trigger signal with POST method by adding required execution Id (eg 1234) : http:// <IP:PORT> /app-rest/service/runtime/executions/1234.
You can also Trigger the task using the Runtime Service.
- ex = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).activityId(“myServiceTask”).singleResult();
- runtimeService.trigger(ex.getId(), this.variables);
Monitoring External Integrations
Lastly, using an Asynchronous Triggerable Service task allows you monitor and restart calls to External systems. As discussed earlier, asynchronous tasks are added to a queue to be run. If the service task fails on its execution it will be re-run by the job executor. (The number of times it is re-run can be configured). As our service task only makes a request to the ESB, it is unlikely that it will fail. However, if the ESB is not reachable (potentially because the network is bad or the ESB is down) then the call will be remade. If after a number of retries it has still failed it will be added to the deadletter queue in Flowable. This is accessible from the Flowable Admin application. Tasks that have failed can be re-run by adding them back into the queue.
As the actual work for the tasks is being done by External Applications we also passed back in as variables the success/failure status of the external processing to the workflow when making the Trigger call back to