Externally triggered processes: How to do it correctly?

Hello dear camundians,

sorry, this is another code question from a camunda beginner. I am currently implementing a web service that should allow triggering camunda processes. In a first toy implementation everything looks fine, the process gets started and all service-task delegates are called (spring bean implementation using a shared process engine).

What I ultimately want to achieve is this basic scenario:

  • the web-service method passes variables to the process and starts it
  • the web-service thread should then wait for the process to finish (only service tasks are involved)
  • the (now modified) process variables should be retrieved.

Right now I am basically trying to do

ProcessInstance instance = runtimeService.startProcessInstanceByKey("test",oldVars);
//awkwardly wait for the process to finish
while (!instance.isEnded()) {
Thread.sleep(500); }
Map<String, Object> newVars = rts.getVariables(instance.getId());

This, however, does not work (the execution doesn’ t exist anymore after completion, so I cannot access the variables… I am getting an org.camunda.bpm.engine.exception.NullValueException).

What would be the correct way to implement something like this?

Cheers

Felix

Hi @fbo,

Once a process instance is finished, you can no longer use the non-history services to access its state because it has been removed from the runtime tables. Instead, you could use HistoryService and its method #createHistoricVariableInstanceQuery to find the variables you are looking for.

If your process contains only service tasks and no asynchronous continuations or other wait states like catching events, then the Methode RuntimeService#startProcessInstanceByKey blocks until the process instance has finished. You don’t need to wait for it in a loop. In addition, the loop does not work anyway because the #isEnded property of a ProcessInstance object that is returned by the API does not change. The returned object is rather an immutable copy of the state in which the process instance was when the API call returned. If you wanted to track changes that way, you would have to make process instance queries repeatedly.

I hope that helps.

Cheers,
Thorben

Hi @thorben,

thank you for your answer - I have implemented it now using RuntimeService#startProcessInstanceByKey and it works. However, that seems pretty cumbersome and makes me worry about performance. I reckon there are DB queries involved here?

Is there no immediate solution to intercept the final process variables at the time the process finishes?

Cheers

Felix

Hi @fbo,

As an alternative, you can register an execution listener on the process instance’s end event. Then you can access all the variables you need and make them available in some intermittent store, such as a ThreadLocal. After the engine API call returns, you can read the variables from there. That would avoid the additional history queries. With that solution, you’ll have to make sure to properly manage the ThreadLocal to avoid memory leaks.

I personally prefer a simple solution over a seemingly better performing solution as long as performance is not critical.

Cheers,
Thorben