Calling an external API in Service task and wait for callback in next process


#1

Hello,

I am very new to Camunda. I am trying to achieve a scenario where one service task will call a external REST API to validate some data (it might take few hours to validate in the external system) and it should be async and once the next process (may be a receive task) gets some kind of callback it will continue. Please suggest what will be the best approach to achieve this.
Please find below the image for reference. I have created one more box at top just to simulate external system.


#2

Is this being built for execution or simply for design?


#3

Hello Niall,

We are planning to build it for execution but what I mean was “External System” Pool/Participant is only for simulation as an external system.
Objective is to call a REST API to pass some data along with file name and the external system will process it but may take some time (an hour may be and so thinking of async task) and the next task will wait for the response of the request submitted in the previous step. Please find below the complete BPMN. Tasks marked inside red circle “Call external Service for data validation” is calling external system (java delegate calling external REST API) and I am thinking “Wait for Response” should process once it receive the response from the external application. Is this the best way or please suggest to achieve it in better way.
Once response received we will process it based on the response.


#4

What you have there is pretty close to what i would suggest with a small change.
I would used a “collapsed pool” instead of send a message to a lone task in a pool. You can see an example here:
https://cawemo.com/shares/a544ad40-48e8-477b-94e2-23f69e182205


#5

Thanks Niall,

It will be really helpfull if there any java code (from the process prospective) available to help us to achieve this . We are able to send a REST call to external system but how do we check it in the next step/task(receiver task) while waiting?


#6

In the process displayed, once the the rest call has been successful the process moves to the receive task and then commits. Waiting until the external system sends a message to the instance that it has finished.
The external system can do this using the correlate message rest call. The Camunda process will wait on the receive task for as long as it takes for the external system to send the message.

The receive task itself does not need to run any code - it just needs a message name.


#7

Thanks @Niall .
So while calling the external system using REST (Call external Service for data validation) we just have to write the code to call the external API nothing else and the external system will call the receiver task with correlation message.
Please find below the screen shot for the “Call external Service for data validation” task properties (whether it should be Asynchronous ??).

In the java class we are calling the external API. Once the process is completed external system should send response valid “true/false” along with correlation message. Correct my understanding if I am wrong.

Any example code will really help my understanding . .


#8

Your understanding of how the message correlation works is correct.

I wouldn’t worry too much about making the service task Asynchronous. The Receive task by default will commit the transaction and therefore ensure that the engine is not waiting in memory for the return message from the external system.


#9

Thanks @Niall

I just tried to send the corelation message via REST API. I am getting the following exception.

{
“type”: “RestException”,
“message”: “org.camunda.bpm.engine.MismatchingMessageCorrelationException: Cannot correlate message ‘Message_38t37h0’: No process definition or execution matches the parameters”
}

Please find below my payload.
URL : http://localhost:8080/engine-rest/message
Method: POST

{
“messageName” : “Message_38t37h0”,
“businessKey” : “aBusinessKey”,
“correlationKeys” : {
“id” : {“value” : “d7e0e023-ff68-11e7-ae92-9cad97d34f79”, “type”: “String”}
},
“processVariables” : {
“isValid” : {“value” : true, “type”: “Boolean”}
}
}

Please find below the screen shots.

Please suggest if I am passing anything wrong


#10

The payload you’ve passed does not match what the process instance is expecting

For this to work the process must have a business key called aBusinessKey and it also needs a process variable called Id with the vaule d7e0e023-ff68-11e7-ae92-9cad97d34f79

It’s not likely the case in your instance. You either need to create a business key when you start the process OR created a variable to correlate the message or both.


#11

Thanks @Niall

I got it now and able to process the receive task.


#12

@priyank

I am dealing with the same issues you mentioned in your post.
Might it be possible, that you give an example, how you did your java implementations?
Calling the rest ws is not the problem, but delivering the ID’s to make the callback by message correlation is the challenge.
Best regards,
Manuel


#13

@Niall

Hi @Niall

Couldt this also be achieved by using a java delegate that extends AbstractBpmnActivityBehavior. That class will have to implement both a execute and signal method.

When the delegate is finished executed (calls an external system (also containing the process instance id)), the task will wait until the signal method is called with the correlation process instance id. Then it will continue to the next task in the process.

In our system, the execute method puts a message on a kafka queue (which the external system is listening on). We have a kafka listener class that listens on another topic from kafka, where the response from the external system will arrive. When it arrives, we call “processEngine.getRuntimeService().signal(message.getId());”, which will hit the signal method in the java delegate class. This finishes the task, so it continues to the next task.

Is this a correct way to do it?

Br

Frank


#14

I’m also currently working with asynchronous external rest-api invocation. Looks like it will be better (from multi-instance correlation and error handling perspective) to have a single task in bpmn diagram instead of sending tasks and receive task\message events. As far as I understand it’s possible to realize in two ways: AbstractBpmnActivityBehavior or External task. But I completely doesn’t know which approach will be better.


#15

Hi @thedenische,

the External Task implementation is more powerful as you can use externalTaskService.failure() and externalTaskService.bpmnError() in cases when something goes wrong with your service response.

The AbstractBpmnActivityBehavior can’t create an incident during signal() i.e. when the task cannot be completed.

Hope this helps, Ingo


#16

Thank you for your response. This is exactly that I am trying to find out for me. What approach is the best practice and why.

But I think for AbstractBpmnActivityBehavior I’m able to throw RuntimeException or BpmnException in signal() instead of externalTaskService.failure() and externalTaskService.bpmnError() for External Task.


#17

Hi @thedenische,

in signal() it’s impossible to create an incident (https://docs.camunda.org/manual/7.11/user-guide/process-engine/incidents/) that you can inspect in the cockpit: https://docs.camunda.org/manual/7.11/webapps/cockpit/bpmn/failed-jobs/

Throwing a RuntimeExcepetion in signal() will rollback the transaction.

Recently a customer switched from AbstractBpmnActivityBehavior to external tasks for this reason.

Hope this helps,


#18

When I’m trying to throw RuntineException in simple ServceTask (Expression that calls java method) it creates incedent. Does AbstractBpmnActivityBehavior have different behaviour or I missed something.


#19

Hi @thedenische,

AbstractBpmnActivityBehavior creates the incident only, when sending your (asynchronous) request fails. As the response has to be translated into signal(), you can not create the incident here.

Hope this helps, Ingo


#20

Hi @Ingo_Richtsmeier.
Thank you a lot for sharing your experience.