cancel
Showing results for 
Search instead for 
Did you mean: 

RuntimeService.setVariable Bug in Activiti 5.19.0.1

andrew_pach
Champ in-the-making
Champ in-the-making
I am in the process of upgrading from Activiti 5.16.3 to Activiti 5.19.0.1 and came across what appears to be a bug when setting variables under certain circumstances.

In a local JUnit test, I have a workflow which contains a boundary event 1 second timer which in turn invokes a custom JavaDelegate which sets a workflow variable using RuntimeService.setVariable. This eventually invokes VariableScopeImpl.createVariableInstance, however, this method doesn't yet have the variableInstances map initialized (i.e. it is null), so the variable doesn't get set in the map. Then when the workflow ends and the transaction commits, Activiti attempts to insert the process instance history records and delete the process instance runtime instance records. However, since the variable I set isn't present in the variableInstances map, Activiti winds up not deleting it from the runtime instance and in turn, a constraint violation exception is thrown (see below) since it can't delete the runtime process instance with a leftover variable still present.

A simple workaround I can use for the time being is to call RuntimeService.getVariables before I call setVariable which initializes the variableInstances map and fixes the problem. However, I would appreciate it if you could fix this issue.

Thank you.

Exception that is thrown due to the above problem:
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database.  Cause: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "ACT_FK_VAR_EXE: PUBLIC.ACT_RU_VARIABLE FOREIGN KEY(EXECUTION_ID_) REFERENCES PUBLIC.ACT_RU_EXECUTION(ID_) ('4')"; SQL statement:
delete from ACT_RU_EXECUTION where ID_ = ? and REV_ = ? [23503-187]
### The error may involve org.activiti.engine.impl.persistence.entity.ExecutionEntity.deleteExecution-Inline
### The error occurred while setting parameters
### SQL: delete from ACT_RU_EXECUTION where ID_ = ? and REV_ = ?
### Cause: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "ACT_FK_VAR_EXE: PUBLIC.ACT_RU_VARIABLE FOREIGN KEY(EXECUTION_ID_) REFERENCES PUBLIC.ACT_RU_EXECUTION(ID_) ('4')"; SQL statement:
delete from ACT_RU_EXECUTION where ID_ = ? and REV_ = ? [23503-187]
9 REPLIES 9

vasile_dirla
Star Contributor
Star Contributor
Hi,
Thanks for rising the flag for this problem.
would be great if you could provide here also your local UnitTest (since you already have it).

if you have also the fix for it you can just create a PR and then take all the credit.

meantime I'll try to reproduce it Smiley Happy

andrew_pach
Champ in-the-making
Champ in-the-making
Hi Vasile and thanks for your quick response.

My JUnit has too many other dependencies to add it here, but below is the workflow that causes the problem. The MockJavaDelegate simply sets a variable as also noted below. The workaround is to add a call to getVariables right before the setVariable method.

I didn't dig into the VariableScopeImpl class too much to know what the proper fix should be. A possible fix would be to add a "ensureVariableInstancesInitialized();" method invocation at the beginning of the createVariableInstance method at line 690 (like exists in many other methods), but I'm not sure if that's the right approach since the author appears to be relying on the map being null to mean something.

MockJavaDelegate functionality:
<code>
runtimeService.setVariable(executionId, "testVariable", "testValue");
</code>

Test Workflow:
<code>
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlnsSmiley Surprisedmgdc="http://www.omg.org/spec/DD/20100524/DC" xmlnsSmiley Surprisedmgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="test" name="testTimerWorkflow" isExecutable="true">
    <startEvent id="startevent1" name="Start"/>
    <userTask id="usertask1" name="usertask1" activiti:candidateGroups="testGroup"/>
    <boundaryEvent id="boundarytimer1" name="boundarytimer1" attachedToRef="usertask1" cancelActivity="true">
      <timerEventDefinition>
        <timeDuration>PT1S</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <serviceTask id="servicetask1" name="servicetask1" activiti:class="MockJavaDelegate"></serviceTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <sequenceFlow id="flow2" sourceRef="boundarytimer1" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow3" sourceRef="servicetask1" targetRef="endevent1"></sequenceFlow>
  </process>
</definitions>
</code>

andrew_pach
Champ in-the-making
Champ in-the-making
I haven't seen any more information regarding this issue. Is it possible somebody could create a bug for this issue or let me know what I need to do to create one myself?

jbarrez
Star Contributor
Star Contributor
Hi Andrew, was planning on taking a look at the issue tomorrow morning.

Is the exception happening even on this simple process?
Did you try using the execution.setVariable() instead? What happens then?

andrew_pach
Champ in-the-making
Champ in-the-making
The only test I performed was using the workflow I mentioned previously. I did modify the test to use the execution to set the variable as you suggested and that worked. So it looks like the issue is centered around setting the variable through the runtimeService using the execution Id.

However, we rely on using the runtimService in situations when we set the variable in a separate thread. In this scenario, the execution doesn't seem to set the variable properly since it doesn't exist when queried via the historyService (see below). The use case that uses a separate thread exists because we perform long running processing in a separate thread and use a receiveTask to notify the workflow when the background processing is complete.

<code>
List<HistoricVariableInstance> historicVariableInstances = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId()).list();
<code>

andrew_pach
Champ in-the-making
Champ in-the-making
Following up to see if anything has bee done on this issue of if there is a bug # I can use to track it's progress.

andrew_pach
Champ in-the-making
Champ in-the-making
Bug was created to track this issue:
https://activiti.atlassian.net/browse/ACT-4115

jbarrez
Star Contributor
Star Contributor
Thanks, we'll follow up there.

balsarori
Champ on-the-rise
Champ on-the-rise
In a JavaDelegate

[java]
execution.setVariable("testVariable", "testValue");
[/java]

should be used