How to handle exceptions and restart the process

Hi,

I must admit, that I am new to flowable. For our workflow I created a process - which is not very complex. It is a chain of Web service calls:

<?xml version="1.0" encoding="UTF-8"?>
  <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
  <process id="test" name="my-test" isExecutable="true">
    <startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
    <serviceTask id="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C" name="web service 1" flowable:delegateExpression="#{webservice1}"></serviceTask>
    <sequenceFlow id="sid-31888C01-3813-4060-AE75-0972D11C0052" sourceRef="startEvent1" targetRef="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C"></sequenceFlow>
    <serviceTask id="sid-46B4A7B1-4951-40E3-991C-233C0CBF3C6D" name="web service 2" flowable:delegateExpression="#{webservice2}"></serviceTask>
    <sequenceFlow id="sid-5650D058-A71D-4A31-BB4D-CBECC13D924B" sourceRef="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C" targetRef="sid-46B4A7B1-4951-40E3-991C-233C0CBF3C6D"></sequenceFlow>
    <endEvent id="sid-38EA8BF7-4A69-4F04-818F-B5F77184234A"></endEvent>
    <sequenceFlow id="sid-377708A6-B694-43CF-9D39-92846E3512FA" sourceRef="sid-46B4A7B1-4951-40E3-991C-233C0CBF3C6D" targetRef="sid-38EA8BF7-4A69-4F04-818F-B5F77184234A"></sequenceFlow>
  </process>
</definitions>

My problem is, that I am not sure how handle exceptions which can occur during the web service calls, i.e. timeouts. I want to be able to restart a service in case of an exception. So I added a mapException tag and and error event boundary:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">

  <error id="technical-error" errorCode="500" />
  
  <process id="test" name="my-test" isExecutable="true">
    <startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
    <serviceTask id="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C" name="web service 1" flowable:delegateExpression="#{webservice1}">
	  <extensionElements>
		  <flowable:mapException errorCode="500" andChildren="true">org.flowable.common.engine.api.FlowableException</flowable:mapException>
	  </extensionElements>
	</serviceTask>
    <sequenceFlow id="sid-31888C01-3813-4060-AE75-0972D11C0052" sourceRef="startEvent1" targetRef="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C"></sequenceFlow>
    <serviceTask id="sid-46B4A7B1-4951-40E3-991C-233C0CBF3C6D" name="web service 2" flowable:delegateExpression="#{webservice2}">
	  <extensionElements>
		  <flowable:mapException errorCode="500" andChildren="true">org.flowable.common.engine.api.FlowableException</flowable:mapException>
	  </extensionElements>	
	</serviceTask>
    <sequenceFlow id="sid-5650D058-A71D-4A31-BB4D-CBECC13D924B" sourceRef="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C" targetRef="sid-46B4A7B1-4951-40E3-991C-233C0CBF3C6D"></sequenceFlow>
    <endEvent id="sid-38EA8BF7-4A69-4F04-818F-B5F77184234A"></endEvent>
    <sequenceFlow id="sid-377708A6-B694-43CF-9D39-92846E3512FA" sourceRef="sid-46B4A7B1-4951-40E3-991C-233C0CBF3C6D" targetRef="sid-38EA8BF7-4A69-4F04-818F-B5F77184234A"></sequenceFlow>
    <boundaryEvent id="sid-F0C724A8-A5EE-4627-99FC-AA847E89919C" attachedToRef="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C">
      <errorEventDefinition errorRef="technical-error"></errorEventDefinition>
    </boundaryEvent>
    <boundaryEvent id="sid-0ADEE078-6114-4490-89B8-11B2F246E58C">
      <errorEventDefinition errorRef="technical-error"></errorEventDefinition>
    </boundaryEvent>
    <intermediateCatchEvent id="sid-FE94662F-4CCF-4AB0-8A42-192B9E449246">
      <timerEventDefinition>
	    <timeCycle>* 0/1 * * * ?</timeCycle>
	  </timerEventDefinition>
    </intermediateCatchEvent>
    <sequenceFlow id="sid-36E41A84-C8AE-4DF3-863C-BFA0B9D9670B" sourceRef="sid-0ADEE078-6114-4490-89B8-11B2F246E58C" targetRef="sid-FE94662F-4CCF-4AB0-8A42-192B9E449246"></sequenceFlow>
    <intermediateCatchEvent id="sid-385FE343-F83D-49E8-ACFF-E9BEC2AE3D1F">
      <timerEventDefinition>
	    <timeCycle>* 0/1 * * * ?</timeCycle>
	  </timerEventDefinition>
    </intermediateCatchEvent>
    <sequenceFlow id="sid-767E5D70-275F-4408-9240-A1F623F9EC0B" sourceRef="sid-F0C724A8-A5EE-4627-99FC-AA847E89919C" targetRef="sid-385FE343-F83D-49E8-ACFF-E9BEC2AE3D1F"></sequenceFlow>
    <sequenceFlow id="sid-96526E68-B582-4AE3-8B4E-93D2F72CFE7A" sourceRef="sid-385FE343-F83D-49E8-ACFF-E9BEC2AE3D1F" targetRef="sid-9A8A0309-A5CE-4CEB-BFFA-69D7CCF5383C"></sequenceFlow>
    <sequenceFlow id="sid-525218F8-E9ED-4D6A-BB66-F9D024E6E9CA" sourceRef="sid-FE94662F-4CCF-4AB0-8A42-192B9E449246" targetRef="sid-46B4A7B1-4951-40E3-991C-233C0CBF3C6D"></sequenceFlow>
  </process>
</definitions> 

In case of an exception, it is handled in the (Java) service task and re-thrown as a Flowable exception. Every minute the service tries to re-send the message.

Is it correct to handle exceptions that way or are there other (better) possibilities to handle them, i.e. a global exception handler or something like that?

And is there a build-in way in flowable to find out what exception was thrown (i.e. using a specific service, listener …)? I handle the exception in the service task and it would be possible to store the exception in a process variable for information purpose (to inform the user, that this process is currently trying to re-send the message because of exception X).

I appreciate your help.

Best regards,
Daniel

No one? There must be somebody who has done this before …

If you are attempting to model the error flow, you can have your service task catch and rethrow BpmnErrors instead. You can then use Error Boundary Event to flow to tasks adding whatever process variables you’d like.

An alternative is making the calls async. If they fail, they will be retried later automatically (and the exception gets stored and can be queried through the managementService).

Sorry for the late reply. Thank you very much.
Your suggestion is very good. I will use your approach. :+1:

Sorry for the late reply. Unfortunately, it is not possible to use async calls.
But, I was wondering how an exception can be queried through managementService. Can you provide an example? Thanks again.

Exceptions are only persisted when making it async. E.g. the return result of managementService#createDeadLetterJobQuery will contain the exceptions.

Otherwise, you’d have to store the exception yourself as a variable.