Why does Camunda perform updates when reading variables?

I’ve found the following in my log files. I was surprised seeing UPDATE problem after calling getVariables(). I also looked at the DB schema and I do not see anything like ‘last access time’.

org.camunda.bpm.engine.OptimisticLockingException: ENGINE-03005 Execution of 'UPDATE VariableInstanceEntity[5813e3e6-ae83-11ec-80f8-001a4a3b0259]' failed. Entity was updated by another transaction concurrently.
        at org.camunda.bpm.engine.impl.db.EnginePersistenceLogger.concurrentUpdateDbEntityException(EnginePersistenceLogger.java:136)
        at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.handleConcurrentModification(DbEntityManager.java:413)
        at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flushDbOperations(DbEntityManager.java:356)
        at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flushDbOperationManager(DbEntityManager.java:323)
        at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flush(DbEntityManager.java:295)
        at org.camunda.bpm.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:272)
        at org.camunda.bpm.engine.impl.interceptor.CommandContext.close(CommandContext.java:188)
        at org.camunda.bpm.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:119)
        at org.camunda.bpm.engine.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:72)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
        at org.camunda.bpm.engine.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:70)
        at org.camunda.bpm.engine.impl.interceptor.ProcessApplicationContextInterceptor.execute(ProcessApplicationContextInterceptor.java:70)
        at org.camunda.bpm.engine.impl.interceptor.CommandCounterInterceptor.execute(CommandCounterInterceptor.java:35)
        at org.camunda.bpm.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:33)
        at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariablesTyped(RuntimeServiceImpl.java:302)
        at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariablesTyped(RuntimeServiceImpl.java:297)
        at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariables(RuntimeServiceImpl.java:292)
        at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariables(RuntimeServiceImpl.java:85)

Hi @andrius,

the engine uses optimistic locking and checks the revision (REV_) column in the database: Transactions in Processes | docs.camunda.org

Hope this helps, Ingo

I’m not sure I got your point. The link you gave says Modifications (UPDATEs and DELETEs) always attempt to update the revision.
But I do not expect RuntimeServiceImpl.getVariables to perform any modifications. I thought it only SELECTs something from the database.

I’m trying to understand what is impact of RuntimeServiceImpl.getVariables on the database. I thought it is a light read-only operation, which can be performed often without being too cautious. The stacktrace kind of indicates it may cause UPDATE VariableInstanceEntity which makes me wary.

Hi @andrius,

from the stacktrace I see that the getVariables is part of an transaction handled by Spring. What else happens in this transaction?

How and where do you call the RuntimeService?

What else happens in this transaction?
How and where do you call the RuntimeService?

It is called as part of REST GET to feed UI app with some data from DB and Camunda (embedded in spring-boot app).
As far as I know everything in that transaction is read-only. I’m just not sure about Camunda part. Can I count on getVariables being read-only?

I had a hypothesis getVariables could fail because of other transactions updating those variables. But because of your questions I think there can be another reason.

I had encountered the same problem.

getVariables() and similar methods can trigger database updates under certain conditions. Camunda will track all mutable variables, which you read in Java Code for changes - and upon ending the current transaction all changed will be written to the database. Camunda does this by serializing the Java-Class again and comparing this to the saved bytes in the database. But certain effects can lead to different bytes when serializing again (different serializer parameters, generic type arguments, new java or type version) - which will then unexpectantly trigger a database write.

I’ve created a workaround with a helper class, which will suppress the variables from being tracked. But be warned this helper class uses reflection and thus may stop working with any major camunda update (although the reflected class is stable for years and so it is very unlikely)

Thanks for sharing. Note that with the latest alphas and the coming 7.19.0 release, we have a new config option implicitVariableUpdateDetectionEnabled to disabled this behavior (see Process Engine Configuration | docs.camunda.org too).