Variable is null but is present in database

Hi,

I’m using

processEngine.getRuntimeService().getVariable(executionId, variableName)

inside a JavaDelegate to get the value of a variable, where the executionId is the process instance id of the root process. The processEngine returns null, but if I check the database the variable is present in the table act_ru_variable and is not null. The value was set via a call to

processEngine.getRuntimeService().setVariable(executionId, variables)

earlier from outside the process while the JavaDelegate was already active and waiting for a lock.

Is an old value from the cache being used? If yes, is there anything I can do to update the cache while the JavaDelegate is active? Or is there another way to update the variable from outside the process that will also update the cache?

Thank you in advance for your help!

Okay, I solved the problem by not reading the variable at the start of the JavaDelegate. If I only read it after the variable is set, it’s read correctly.

Hi @Willy,

inside a Java Delegate you should use execution.getVariable("myName"); where execution is the object passed as a parameter.

It’s easier to type and to read.

Hope this helps, Ingo

I’m having a similar problem now. I have two parallel service tasks which both check, if the other one has set its variable already and if it has, “success” is printed. Here are the process definitions:

<bpmn:process id=“TestParallelVariableChangeParentProcess” name=“TestParallelVariableChangeParentProcess” isExecutable=“true”>

<bpmn:startEvent id="Start" name="Start" />

<bpmn:parallelGateway id="Fork" />

<bpmn:callActivity id="TestParallelVariableChangeChildProcess1" name="TestParallelVariableChangeChildProcess1" calledElement="TestParallelVariableChangeChildProcess" >
    <bpmn:extensionElements>
        <camunda:in variables="all" />
        <camunda:out variables="all" />
        <camunda:inputOutput>
            <camunda:inputParameter name="thisname">p1</camunda:inputParameter>
            <camunda:inputParameter name="othername">p2</camunda:inputParameter>
        </camunda:inputOutput>
    </bpmn:extensionElements>
</bpmn:callActivity>

<bpmn:callActivity id="TestParallelVariableChangeChildProcess2" name="TestParallelVariableChangeChildProcess2" calledElement="TestParallelVariableChangeChildProcess" >
    <bpmn:extensionElements>
        <camunda:in variables="all" />
        <camunda:out variables="all" />
        <camunda:inputOutput>
            <camunda:inputParameter name="thisname">p2</camunda:inputParameter>
            <camunda:inputParameter name="othername">p1</camunda:inputParameter>
        </camunda:inputOutput>
    </bpmn:extensionElements>
</bpmn:callActivity>

<bpmn:parallelGateway id="Join" />

<bpmn:endEvent id="End" name="End" />


<bpmn:sequenceFlow id="ToFork" name=""
                    sourceRef="Start"
                    targetRef="Fork" />

<bpmn:sequenceFlow id="ToTestParallelVariableChangeChildProcess1" name=""
                    sourceRef="Fork"
                    targetRef="TestParallelVariableChangeChildProcess1" />
<bpmn:sequenceFlow id="FromTestParallelVariableChangeChildProcess1" name=""
                    sourceRef="TestParallelVariableChangeChildProcess1"
                    targetRef="Join" />

<bpmn:sequenceFlow id="ToTestParallelVariableChangeChildProcess2" name=""
                    sourceRef="Fork"
                    targetRef="TestParallelVariableChangeChildProcess2" />
<bpmn:sequenceFlow id="FromTestParallelVariableChangeChildProcess2" name=""
                    sourceRef="TestParallelVariableChangeChildProcess2"
                    targetRef="Join" />

<bpmn:sequenceFlow id="ToEnd" name=""
                    sourceRef="Join"
                    targetRef="End" />

</bpmn:process>

<bpmn:process id=“TestParallelVariableChangeChildProcess” name=“TestParallelVariableChangeChildProcess” isExecutable=“true”>

<bpmn:startEvent id="Start" name="Start" camunda:asyncBefore="true" />

<bpmn:serviceTask id="SetVariable" name="SetVariable" camunda:class="test.TestParallelVariableChangeServiceTask" camunda:asyncAfter="true" />

<bpmn:endEvent id="End" name="End" />

<bpmn:sequenceFlow id="ToSetVariable" name=""
                    sourceRef="Start"
                    targetRef="SetVariable" />
<bpmn:sequenceFlow id="ToEnd" name=""
                    sourceRef="SetVariable"
                    targetRef="End" />

</bpmn:process>

and this JavaDelegate:

package test;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

public class TestParallelVariableChangeServiceTask implements JavaDelegate {

private static final Object LOCK = new Object();

@Override
public void execute(DelegateExecution execution) throws Exception {
    String thisName = (String)execution.getVariable("thisname");
    String otherName = (String)execution.getVariable("othername");
    
    DelegateExecution superProcessInstance = execution.getProcessInstance().getSuperExecution().getProcessInstance();
    
    synchronized (LOCK) {
        if (superProcessInstance.hasVariable(otherName)) {
            System.out.println("success");
        } else {
            System.out.println(thisName + " was not successful");
            superProcessInstance.setVariable(thisName, true);
        }
    }
    
}

}

The output is

p1 was not successful
p2 was not successful

and two OptimisticLockingExceptions are thrown:

ENGINE-14006 Exception while executing job 98245: : org.camunda.bpm.engine.OptimisticLockingException: ENGINE-03005 Execution of ‘UPDATE VariableInstanceEntity[98203]’ failed. Entity was updated by another transaction concurrently.
[stack trace]

ENGINE-14006 Exception while executing job 98245: : org.camunda.bpm.engine.OptimisticLockingException: ENGINE-03005 Execution of ‘UPDATE VariableInstanceEntity[98203]’ failed. Entity was updated by another transaction concurrently.
[stack trace]

Is there anything I can do to make sure, that “success” is being printed?

The original problem is, that I have two or more parallel paths that are only allowed to proceed to the join gateway after all paths have finished.

I can get it to work if I use a custom HistoryEventHandler, but I was wondering if there is a simpler way.

I solved it now, the custom HistoryEventHandler doesn’t really help, but the key is, to change the variable in a new Thread, because then it’s set immediately and not after the next asyncBefore/asyncAfter.