cancel
Showing results for 
Search instead for 
Did you mean: 

Inconsistent procvar behaviour

marcus1
Champ in-the-making
Champ in-the-making
I found some strange behaviour regarding the storing and updating of process variables. Suppose we have the following process:

Process A:
Service 1 -> Task 1 -> Service 2 -> Task 2 -> Service 3

Service 1 creates a new process variable:

Book book = new Book("12345");
execution.setVariable("book", book);
Service 2 changes a property:

Book book = execution.getVariable("book");
book.setTitle("Activiti in Action");
Service 3 prints the content of the process variable:

Book book = execution.getVariable("book");
System.out.println("book=" + book);
Result: book=Book [isbn=12345, title=Activiti in Action]

This is as (I) expected. However, now we remove Task 1. Lets see what happens.

Process B:
Service 1 -> Service 2 -> Task 2 -> Service 3

Result: book=Book [isbn=12345, title=null]

This is strange… the variable is not updated whereas it was in the first process.

Conclusion
It seems that changes to process variables are only persisted if there is a waitstate between the creation and the update of the var.

Also, when debugging this issue I noticed that VariableType.serialize is called twice every time setVariable (or rather createVariableLocal) is called: once by VariableInstanceEntity.createAndInsert and once by VariableScopeImpl.setVariableInstanceValue.

I've tried to attach a patch with a testcase, but this results in the error "The extension diff is not allowed"…
6 REPLIES 6

trademak
Star Contributor
Star Contributor
Hi,

Can you attach a working test project for this problem?

Best regards,

marcus1
Champ in-the-making
Champ in-the-making
The forum doesn't seem to allow attaching files:

The extension diff is not allowed. (Same happens with other extensions)

So I made a Jira issue:

http://jira.codehaus.org/browse/ACT-934

mathiasd
Champ in-the-making
Champ in-the-making
I think your problem is similar to this one : http://jira.codehaus.org/browse/ACT-820, discussed here : http://forums.activiti.org/en/viewtopic.php?f=6&t=1720 and here http://forums.activiti.org/en/viewtopic.php?f=6&t=2394

You need to re-affect the variable each time you update it :


Book book = execution.getVariable("book");
book.setTitle("Activiti in Action");
execution.setVariable("book", book);

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
@Mathias: Good catch, I missed that…

marcus1
Champ in-the-making
Champ in-the-making
@Mathias: good to know that other people have encountered this issue. I hope we can find a solution to this Smiley Happy

It seems to me that the cause of the problem is as follows.

Lets first look at what happens in case of Process A, which (AFAIK) works as intended.

When setVariable is called from Service1, first the list of variableInstances is initialized. Then a new VariableInstanceEntity is created. The call hierarchy is as follows:

ExecutionEntity(VariableScopeImpl).setVariable
—-ExecutionEntity(VariableScopeImpl).createVariableLocal
——–VariableInstanceEntity.createAndInsert
————VariableInstanceEntity.create
—————-VariableInstanceEntity.setValue
——————–SerializableType.setValue
————————ValueFields.setCachedValue
—————————-cachedValue = …
————————cachedValue = …

So the variable is created and added to the SqlSession, and the cachedValue is set (twice actually).

The next step in the process is a task, so the db session is flushed, causing the ExecutionEntity (and the variable) to be written to the database.

After that the next step is Service2, which calls getVariable. The call hierarchy looks like this:

ExecutionEntity(VariableScopeImpl).getVariable
—-ExecutionEntity(VariableScopeImpl).ensureVariableInstancesInitialized (not initialized yet, so fetch from db)
—-VariableInstanceEntity.getValue (cachedValue is null)
——–SerializableType.getValue (only called if cachedValue is null)
————DbSqlSession.addDeserializedObject

So ultimately getVariable causes DbSqlSession.addDeserializedObject to be called. As I understand it, this ensures that variables with updated values are flushed at the end of the transaction.

What about Process B?

The difference with Process A is the task between Service1 and Service2, so we need only look at what happens in Service2.

When Service2 calls setVariable, this is what happens:

ExecutionEntity(VariableScopeImpl).getVariable
—-ExecutionEntity(VariableScopeImpl).ensureVariableInstancesInitialized (already initialized!)
—-VariableInstanceEntity.getValue (cachedValue is already set!)
——–return cachedValue

In this case, cachedValue is not null, so SerializableType.setValue and thus DbSqlSession.addDeserializedObject is never called!

Solution

In my view, the conceptual solution is simple: addDeserializedObject needs to be called when a new variable is created, not just from getVariable.

marcus1
Champ in-the-making
Champ in-the-making
Getting started

Tags


Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.