Process Instance suspend and activate

Hi
I have a workflow, where, based on certain conditions i need to pause the execution at a certain task, and later resume when another event happens.
Specifically, I need to ingesting a file and then wait for an external application to process it. After the external service processes it, it calls an api indicating the completion, and then i need to resume my execution.

Currently what i have its,

  1. Just before pausing, i save the process instance Id at a database.
  2. Then i suspend the instance using /engine-rest/process-instance//suspended. ( put: {suspended:true} )
  3. When the external application hits my exposed API, i fetch the process instance from DB and then /engine-rest/process-instance//suspended. ( put: {suspended:false} ), thus activating it.

Now the problem is, even though my suspension or activation code doesnt throw any error, it is NOT working. The flow goes right through till the end, unstopped ,without waiting for the API to hit with completion status.

Please help me with this. Or if there is any better way to accomplish this?

Thanks

Hi @Urvashi_Prasad,

From what you’re describing, it’s possible that your process does not enter a wait state once the data is acquired by the external service. Instead it continues to the end.

Can you provide your bpmn model, or at least just the part that you’re using for this functionality?

Also, if you’re not using it, an external service task sounds like a good use case for your problem.

Best,
Nikola

test-bpmn-6.bpmn (7.8 KB)
The bpmn is very usual one, nothing interesting happenning here, in the task “ingest” , after ingesting the files, i call the following method that i have written:

public static void suspendProcessInstance(String processInstanceId, boolean isSuspend) throws Exception {
		try {
			HttpClient httpclient = HttpClientBuilder.create().build();
			String uri = "http://localhost:8080/engine-rest/process-instance/" + processInstanceId + "/suspended";
			//String uri = "http://localhost:8080/engine-rest/process-instance/"+suspended";
			HttpPut httpPut = new HttpPut(uri);
			JSONObject requestJson = new JSONObject();
			
			requestJson.put("suspended", isSuspend);
			StringEntity entity = new StringEntity(requestJson.toJSONString());
			httpPut.setEntity(entity);
			httpPut.addHeader("content-type", "application/json");
			HttpResponse response = httpclient.execute(httpPut);
			if (response != null) {
	            if (response.getStatusLine().getStatusCode() != 204) {
	            	throw new Exception(EntityUtils.toString(response.getEntity(), "UTF-8"));
	            }
			}
		}catch(Exception e) {
			logger.error(e.getMessage());
			throw e;
		}
	}

Hey @Urvashi_Prasad,

Thanks! From the model, I can see that you’re using Service Tasks with delegates to implement your solution. One thing that is confusing me is that you’re using the REST API internally to suspend the process instance. You can do this directly from the process engine (see the first solution).

The first problem is that when you’re sending a ‘Suspend Process Instance’ request to the REST API, the ‘204 response’ actually tells you that your request was valid (see here) and is being executed. However, this does not guarantee that it will be executed immediately, and that your process instance will be suspended at that exact point.

This is related to the second problem. Since you’re using Service Tasks, the engine will execute the code in the Java Delegate (and receive a successful ‘204’ response) and it won’t wait for the external application to finish. It will continue on to the classify task and then finish with the message task. This is done in parallel with your suspend request that you sent through the REST API, and it actually finishes faster than the process instance can be suspended.

One solution, if you want to stick with Service Tasks, is to use an Execution Listener and suspend the process instance there (without using the REST API).

A second solution is to use an External Service Task. By using this one, you actually get the required functionality built in. The process instance will be put into a wait state and you can use the REST API to acquire the external task on the external application side. Once the external application finishes, the process instance resumes. I would recommend this solution if you have access to the external application code.

Cheers,
Nikola

Hi Nikola

Thanks for the response. Both Execution Listener and External Service Task concepts are new to me, I took a look at them just now.
Unfortunately I do not have access to the external application code, so i am left with the solution using Execution Listener.
The documentation says:

The events that can be captured are:

Start and end of a process instance.
Taking a transition.
Start and end of an activity.
Start and end of a gateway.
Start and end of intermediate events.
Ending a start event or starting an end event.

Lets say, i suspend the instance execution at the end of the “ingest” task.
But it has to be activated only when the external application invokes my state change API (hosted on the same server as camunda). So how can i use event listener to activate the instance.? More specifically, when the external application hits my state change API, how do i get hold of this listener and activate the process instance?

Thanks
Urvashi

Hey Urvashi,

If the Camunda engine is embedded in your application, you can use the Runtime Service in your state change API, query for the process instance and activate it (here’s an overview of the available services).

Otherwise, you can use the REST API to resume it as before.

Cheers,
Nikola

The proper solution for my requirement was to use external tasks. Thanks everyone !