cancel
Showing results for 
Search instead for 
Did you mean: 

VariableInstanceEntity was updated by another transaction

jcosano
Champ in-the-making
Champ in-the-making
Sometimes I had this error in my logs files:

org.activiti.engine.ActivitiOptimisticLockingException: VariableInstanceEntity[2002635] was updated by another transaction concurrently
        at org.activiti.engine.impl.db.DbSqlSession.flushUpdates(DbSqlSession.java:390)
        at org.activiti.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:303)
        at org.activiti.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:141)
        at org.activiti.engine.impl.interceptor.CommandContext.close(CommandContext.java:97)
        at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:44)
        at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:33)
        at org.activiti.engine.impl.RuntimeServiceImpl.setVariables(RuntimeServiceImpl.java:97)

I'm not doing anything with transactions… how can I avoid this error?
9 REPLIES 9

jcosano
Champ in-the-making
Champ in-the-making
Invoke code is this:

Map<String, Object> variables = runtime.getVariables(key);
variables.put("noocur",newNum);


runtime.setVariables(key, variables); 

Then, maybe revision number for "variable" change between read and write…

How can I protect this?

maybe I should syncronized this code?

frederikherema1
Star Contributor
Star Contributor
You should make sure that you don't have different threads updating the same variable on the same process instance at the same time using API. This will cause the optimistic locking exceptions you are getting.

jcosano
Champ in-the-making
Champ in-the-making
I had a process A that read a DB2 table, and for each row readed, creates a process instance of process B, and after sleeps 10 minutes.

Process B, create a new process instance of Process C, or update variables from C (if exists).

This problem occurs in process B (updating variables…)

Then, it's true, that maybe a high number of process instance create in process A, are updating the same process instance C…

Now I'm thinking 2 ways..
a) synchro this code
b) capture exception, and read, modify, and save another time…

What do you think is better?

thanks!

frederikherema1
Star Contributor
Star Contributor
If I understand you correctly, you are creating new processes from within another process? Are you using the API (runtimeService.startProcess…) from within a JavaDelagate?

jcosano
Champ in-the-making
Champ in-the-making
You are correct…

Process A… in execution method do a loop with:
engine.getRuntimeService().startProcessInstanceByKey("B",variables);

Process B:
if not exists creates a Process C, or if exist update C variables.

And a high number of A can uses same Process C.

frederikherema1
Star Contributor
Star Contributor
Using the activiti API from within activiti-context (JavaDelegate or TaskListeners) is a bad idea, this can mess up command-context and transactions in activiti. When you start a process-instance this way, the thread that drives the execution (which is used to invoke your code) will be used to run the spawned process instance (until it ends or reaches a wait-state).

About the best way to ensure no process-instances are updated at the same time, I'm not sure either what is the best way to handle this.

jcosano
Champ in-the-making
Champ in-the-making
Process A:
Has two activity: serviceTask and userTask with boundaryEvent for sleep… and return to serviceTask

Process B  is silly:
<startEvent  />
<serviceTask  />
<endEvent  /

Process C is complex (and has integration with people), but first activity it's a userTask…
Then B and C arrives to end or wait state quickly…

And only strange that I see is this transaction problem… and only 6 times en 1 month (maybe I was lucky!! Smiley Tongue )

jbarrez
Star Contributor
Star Contributor
The ActivitiOptimisticLockingException is exactly created for that reason: to indicate that some entity was modified by two (or more) people at the same time.

So what you can do is catch the exception and retry (however, the 'old' value of the variable will then be lost).

jcosano
Champ in-the-making
Champ in-the-making
Old value is not a problem because the most important value it is a counter… and I only need sum 1.

I suppose that finally, I'll catch exception, and try to retry (read-modify-save).. and I'll use a counter for prevent a infinite loop.

Thanks!