How to get the response back from task to the start task

Hi,

I am new to Camunda platform. I have done the set up of camunda platform in my local machine using docker compose. I am successful in running a simple process.
But what I want to know is, how to return back the response of worker logic to the start task?

I have spring boot project where I am triggering the process to start.
Here is my process

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0t46ymm" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.13.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.2.0">
  <bpmn:process id="Process_1pul748" name="start" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1" name="start">
      <bpmn:outgoing>Flow_18vnagg</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_18vnagg" sourceRef="StartEvent_1" targetRef="test_task1" />
    <bpmn:serviceTask id="test_task1" name="test_task">
      <bpmn:extensionElements>
        <zeebe:taskDefinition type="testTenantAPI" />
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_18vnagg</bpmn:incoming>
      <bpmn:outgoing>Flow_03g5wjm</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="Event_197jvv8" name="end">
      <bpmn:incoming>Flow_03g5wjm</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_03g5wjm" sourceRef="test_task1" targetRef="Event_197jvv8" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1pul748">
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="179" y="99" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="186" y="142" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1mwnd4m_di" bpmnElement="test_task1">
        <dc:Bounds x="270" y="77" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_197jvv8_di" bpmnElement="Event_197jvv8">
        <dc:Bounds x="432" y="99" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="441" y="142" width="19" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_18vnagg_di" bpmnElement="Flow_18vnagg">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="270" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_03g5wjm_di" bpmnElement="Flow_03g5wjm">
        <di:waypoint x="370" y="117" />
        <di:waypoint x="432" y="117" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

Here is pom xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.14</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.orchestration</groupId>
	<artifactId>camunda</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>camunda</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/io.camunda/spring-zeebe-starter -->
		<dependency>
			<groupId>io.camunda</groupId>
			<artifactId>spring-zeebe-starter</artifactId>
			<version>8.0.1</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Here is my worker

@Component
public class Worker {

	private static final Logger LOG = LogManager.getLogger(Worker.class);

	@ZeebeWorker(type = "testTenantAPI", autoComplete = true)
	public ResponseDto test(final ActivatedJob job, @ZeebeVariablesAsType SampleDto sampleDto) {
		LOG.debug("worker job called " + sampleDto.getAge());
		// Business logic to be added
		ResponseDto responseDto = new ResponseDto();
		responseDto.setId("001");
		responseDto.setMessage("Success");
		return responseDto;
	}

}

Here is my controller

	@PostMapping(value = "api/v1/test/camunda")
	public void test(@RequestBody SampleDto sampleDto) {
		try {
			client.newDeployResourceCommand().addResourceFromClasspath("testTenantFlow.bpmn").send().join();

			final ProcessInstanceEvent event = client.newCreateInstanceCommand().bpmnProcessId("Process_1pul748")
					.latestVersion().variables(sampleDto).send()
					.join();

			LOG.info(
					"Started instance for processDefinitionKey='{}', bpmnProcessId='{}', version='{}' with processInstanceKey='{}'",
					event.getProcessDefinitionKey(), event.getBpmnProcessId(), event.getVersion(),
					event.getProcessInstanceKey());
		} catch (Exception e) {
			e.printStackTrace();
			LOG.debug("Exception " + e.getMessage());
		}
	}

How I am triggering the flow

http://localhost:8080/api/v1/test/camunda with payload
{
“name”:“karthi”,
“age”:25
}

I am excepting the output for the API as

{
“id”:“001”,
“message”:“Success”
}

How can I get the return value of worker to the start task(which I am hitting it using above URL)

Hi @Karthikeyan_Raju,
Please Upgrade your spring-zeebe-starter to SpringBoot-Starter-Camunda,take a note of version compatibility and upgrade java version
You can also use this approach to deploy the process

Coming to the topic,
Instead of returning value of worker to the start task you can do your business logic like this

@PostMapping(value = "api/v1/test/camunda")
	public void test(@RequestBody SampleDto sampleDto) {
		try {
			client.newDeployResourceCommand().addResourceFromClasspath("testTenantFlow.bpmn").send().join();

// Use a method from another class that performs your business logic
// add the variables of the responseDto to the start event in the below command of sending responseDto variables

			final ProcessInstanceEvent event = client.newCreateInstanceCommand().bpmnProcessId("Process_1pul748")
					.latestVersion().variables(responseDto).send()
					.join();

			LOG.info(
					"Started instance for processDefinitionKey='{}', bpmnProcessId='{}', version='{}' with processInstanceKey='{}'",
					event.getProcessDefinitionKey(), event.getBpmnProcessId(), event.getVersion(),
					event.getProcessInstanceKey());
		} catch (Exception e) {
			e.printStackTrace();
			LOG.debug("Exception " + e.getMessage());
		}

With this approach your responseDto variables will be at the start event and the response of the API can also be configured as responseDto, this approach might not need a jobworker
Hope this Helps

@Praveen_Kumar_Reddy Thanks for your suggestion for the version upgrade but we are using java 8 in our project.

I think I have not conveyed my problem properly, What I want to achieve is, to get the response back to the caller API, like normal asynchronous REST API call.


In the above attached image, I would be triggering the process by triggering an API call with some payload for example for the given product Id I need to create an order. So I will be calling the below API

api/v1/test/camunda with payload required for the subsequent task

By taking the product id from payload,

  1. The 1st job worker(product check) is triggered by zeebe which will have the implementation to validate the product, on success
  2. The 2nd job worker(order placement) is triggered by zeebe which will have the implementation to place order, on success
  3. The 3rd job worker(payment) is triggered by zeebe which will have the implementation for payment, on success
  4. I need to return the order id and few other details as object as response for the API api/v1/test/camunda.

In your explanation you had asked me to set the variable as responseDto but how can I pass the in request object i.e. sampleDto to the worker then? I am bit confused here.

Also if you could share any example code snippet to retrieve variable in the controller class which was set by jobworkers in subsequent tasks.

@Niall could you help me here?

Hi @Karthikeyan_Raju,

It is not simple to get a response that feels like a synchronous call (as everything happens asynchronous in the Zeebe engine), but it is possible.

You can find an example here: https://github.com/camunda-community-hub/camunda-8-examples/tree/main/synchronous-response-springboot

Hope this helps, Ingo

@Ingo_Richtsmeier Thanks for your reply, I have done something as below could you please validate is this proper or not.

	@PostMapping(value = "api/v1/test/camunda")
	public ResponseDto test(@RequestBody SampleDto sampleDto) {
		try {
			client.newDeployResourceCommand().addResourceFromClasspath("testTenantFlow.bpmn").send().join();

			final ProcessInstanceResult event = client.newCreateInstanceCommand().bpmnProcessId("Process_1pul748")
					.latestVersion().variables(sampleDto).withResult().send()
					.join();

			LOG.info(" variable " + event.getVariablesAsType(ResponseDto.class));
			return event.getVariablesAsType(ResponseDto.class);
		} catch (Exception e) {
			e.printStackTrace();
			LOG.debug("Exception " + e.getMessage());
			return null;
		}
	}

Worker as below,

	@ZeebeWorker(type = "testTenantAPI")
	public void test(final ActivatedJob job,
			@ZeebeVariablesAsType SampleDto sampleDto) {
		System.out.println("worker job called " + sampleDto.getAge());
		// Business logic to be added
		ResponseDto responseDto = new ResponseDto();
		responseDto.setId("001");
		responseDto.setMessage("Success");
		client.newCompleteCommand(job.getKey()).variables(responseDto).send();
	}

Hi @Karthikeyan_Raju,

what does your process model look like?

Cheers, Ingo