cancel
Showing results for 
Search instead for 
Did you mean: 

How to retrieve the the return value of the last serviceTask

petercahyadi
Champ in-the-making
Champ in-the-making
Hi, is there a way to retrieve the return value of the serviceTask at the end of the process ?

My BPMN file is as below
<definitions id="definitions" targetNamespace="http://activiti.org/bpmn20"
   xmlns:activiti="http://activiti.org/bpmn" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">
   <process id="testProcess" name="Test process">
      <startEvent id="theStart" />
      <sequenceFlow id='flow1' sourceRef='theStart' targetRef='javaService' />
      <serviceTask id="javaService" name="My Java Service Task"
         activiti:expression="#{myServiceTask.execute(name)}"
         activiti:resultVariableName="myResult" />
      <sequenceFlow id='flow2' sourceRef='javaService'
         targetRef='theEnd' />
      <endEvent id="theEnd" />
   </process>
</definitions>

And my Java serviceTask is as below


@Component
public class MyServiceTask {
   @Transactional
   public String execute(String name) throws Exception {
      
      List<MyTable> myTables = myTableMapper.selectByExample(null);
      int maxId = -1;
      for (MyTable myTable : myTables) {
         maxId = maxId < myTable.getId() ? myTable.getId() : maxId;
      }

      MyTable newMyTable = new MyTable();
      newMyTable.setId(maxId + 1);
      newMyTable.setName(name);
      myTableMapper.insert(newMyTable);

      return "Halo " + name + " !";
   }

   @Autowired
   private MyTableMapper myTableMapper;

}

and here is my main code, which is the one who started the process.

Map<String, Object> input = new HashMap<String, Object>();
input.put("name", "Peter");
ProcessInstance pi = runtimeService.startProcessInstanceByKey("testProcess", input);

i've been trying to retrieve the return value of the java service task, after the startProcessInstanceByKey() finishes executing. but no luck so far, any suggestion on how to do this ?
8 REPLIES 8

bardioc
Champ in-the-making
Champ in-the-making
As your process is completely ended, the result (in the process variable 'myResult') is gone too, unless you set the Activiti History Level to FULL (performance impact) and use the history to retrieve the value.

For synchronous process models, you can add a receive task (named 'receiveTask', see example below) right after your service task or better before your endTask. The process will afterwards wait in this receive task. Then you can query the process using the runtime service for the variable, for example:

ProcessInstance pi = runtimeService.startProcessInstanceByKey("testProcess", input);
String myResult = runtimeService.getVariable(processInstance.getId(), "myResult");
But do not forget to signal the process afterwards to continue and finally end:

Execution execution = runtimeService.createExecutionQuery()
  .processInstanceId(pi.getId())
  .activityId("receiveTask")
  .singleResult();
runtimeService.signal(execution.getId());
Now the process really ended.

Hope it helped,

Heiko

petercahyadi
Champ in-the-making
Champ in-the-making
Hi Heiko,

Thanks for the reply, it worked as you suggested.
i guest this is the workaround for it.
Just wondering if there's a way to get the result variable at the end of the process (something like a return value of a method in java), because by using the receive task, we're actually 'pausing' the process so the variables get saved into DB, and when we try to retrieve the variable using the RuntimeService, this is actually making an sql call to DB which is i think a bit of an 'overhead' process just to get the result value of a process.

bardioc
Champ in-the-making
Champ in-the-making
Hey Peter,

actually there is not, cause a process does by its design not have a result. It simply ends, either positively, with an error or with a cancellation. A "return" value is simply not modeled by BPMN. Only while the process itself is still running, you may send messages or update databases.

trevershick
Champ in-the-making
Champ in-the-making
I'm coming up against this now.  I've not decided on an implementation.
One interim idead i had that should work within some constraints is to have a java service task that will take the 'result' variable and set it in a thread local.

That same thread local would be accessible by the calling code.  So imagine:

// your BPMN
<serviceTask id="exposeReturnValue" activiti:delegateExpression="${ p.d.x.ActivitiReturnValue.getInstance().set(myResult)}"/>

Map<String,Object> args = new HashMap<String,Object>();
runtimeserviice.startProcessBykey("key", args);
// process runs and returns
Object result = ActivitiReturnValue.getInstance().get();
ActivitiReturnValue.getInstance().remove()



This has limitations in that it will only work for synchronous processes with ONE return value.
Also, your calling code MUST clear out the ActivitiReturnValue (a custom class by the way).

I'll post again once i determine my final solution that i plan on using.  I don't care for this myself.  I'm working on using the historyService to pull the value via variableUpdates().  This way i'm not adding any weird behavior and i can support multiple return values (like for multiInstance sub processes).

meyerd
Champ on-the-rise
Champ on-the-rise
I am not sure I am understanding the problem correctly, but couldn't you simply get the value from the history service?
Note that we are currently introducing a new history level in activiti 5.11 which allows you to record only the "last" value of a process variable in history.

jmaru
Champ in-the-making
Champ in-the-making
Hi,

Returning something from an Activiti process is a requirement for us (for an automated flow) and the workarounds that were mentioned above would help. But, are there any plans to do this more naturally which is to optionally allow processes to return 1 or more values? This would be very useful for us through the REST API where we start a process by sending some variables & expect a response with the results from the flow back.

1.) Are there any future plans to include this feature in Activiti?
2.) Has someone extended or embedded Activiti to achieve this? One approach that comes to my mind right now, would be to define a custom task "EndTaskWithResult" which will add the result variables to the Process (by extending Process to add the result variables field) which will be returned to the callee (somehow). I would love to know if someone has done this or has any ideas around this or why this isn't a good idea to begin with if that's the case.

Thanks,
Jeegar Maru

trademak
Star Contributor
Star Contributor
Hi,

As Daniel already pointed out, it would be a good solution to define your own REST/Web service that starts the process instance, then retrieves the value of the process variable via the history service and give the response back. We don't have plans to support this in the REST API.

Best regards,

dananemanoj
Champ in-the-making
Champ in-the-making
Hi there,

One of the clean way to do it is using the Context (Wrapper classes). Pass these wrapper/context class object as an argument to the Service task. Service task will generate the result it and set it on this object which is available even after the life cycle of the process.

Class WorkflowContext{
   RequestParamClass reqParameters;
   ResponseParamClass resParameters;
  
}

- Manoj