TaskServiceImpl.getVariables results into db insertion of history table data

Hi Team

We are exploring camunda for our use.
We have been assuming that TaskServiceImpl.getVariables() will be read only database operation, but looks like it is not. In certain cases, it is doing some data insertion into history table. Is there a reason its working this way? We would like understand it in detail so we can build better API on top of camunda.

Error that we receive because we are marking our operation as read only which calls TaskServiceImpl.getVariables.

“message”: "ENGINE-16004 Exception while closing command context: ENGINE-03004 Exception while executing Database Operation ‘INSERT HistoricVariableUpdateEventEntity[1b4dfebb-94e4-11e7-b60e-0242ac110002]’ with message ‘\n### Error updating database. Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed\n### The error may involve org.camunda.bpm.engine.impl.persistence.entity.HistoricDetailEntity.insertHistoricVariableUpdateEvent-Inline\n### The error occurred while setting parameters\n### SQL: insert into ACT_HI_DETAIL ( ID_, TYPE_, PROC_DEF_KEY_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_INST_ID_, CASE_DEF_KEY_, CASE_DEF_ID_, CASE_INST_ID_, CASE_EXECUTION_ID_, TASK_ID_, NAME_, REV_, VAR_INST_ID_, VAR_TYPE_, TIME_, BYTEARRAY_ID_, DOUBLE_, LONG_, TEXT_, TEXT2_, SEQUENCE_COUNTER_, TENANT_ID_ ) values ( ?, ‘VariableUpdate’, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\n### Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed’.

On debugging, found that it calls following API and tracks some changes across session and tries to insert data into history table to update its cache details. Why? Why would you do this operation as part of get call? I assume there might be background scheduler working which should actually do this job - updating the cache.

Any details provided around this behaviour will help us design and use camunda better.
Can there be any data issue in application which can be causing this issue?

DbOperationManager.getInsertsForType(Class, boolean) line: 103
DbOperationManager.addOperation(DbEntityOperation) line: 67
DbEntityManager.performEntityOperation(CachedDbEntity, DbOperationType) line: 447
DbEntityManager.flushCachedEntity(CachedDbEntity) line: 347
DbEntityManager.flushEntityCache() line: 334
DbEntityManager.flush() line: 275
CommandContext.flushSessions() line: 247
CommandContext.close(CommandInvocationContext) line: 176
CommandContextInterceptor.execute(Command) line: 113
SpringTransactionInterceptor$1.doInTransaction(TransactionStatus) line: 42
TransactionTemplate.execute(TransactionCallback) line: 133
SpringTransactionInterceptor.execute(Command) line: 40
ProcessApplicationContextInterceptor.execute(Command) line: 66
LogInterceptor.execute(Command) line: 30
TaskServiceImpl.getVariablesTyped(String, boolean) line: 206
TaskServiceImpl.getVariablesTyped(String) line: 202
TaskServiceImpl.getVariables(String) line: 198
TaskServiceImpl.getVariables(String) line: 79

Thanks

Which Camunda version do you use?

Hi Thorben
We are using Camunda version 7.6

We found that this happens (getVariable() resulting into history table insertion for byte array) when process instance is started with Map type of variable.

I remember we had a bug that variable updates were sometimes wrongfully triggered when a variable query was made, but I can’t find it right now. Can you check if the problem exists with 7.8.0-alpha3?

Thorben,
What is the corresponding camunda spring boot version? I am using following and getting below error at runtime.
<camunda.version>7.8.0-alpha3</camunda.version>
<camunda.springboot.version>2.2.0</camunda.springboot.version>

Caused by: java.lang.ClassNotFoundException: org.camunda.bpm.engine.impl.bpmn.parser.FoxFailedJobParseListener
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[?:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_131]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[?:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_131]
at org.camunda.bpm.spring.boot.starter.configuration.impl.DefaultFailedJobConfiguration.preInit(DefaultFailedJobConfiguration.java:22) ~[camunda-bpm-spring-boot-starter-2.2.0.jar:2.2.0]
at java.util.Optional.ifPresent(Optional.java:159) ~[?:1.8.0_131]
at org.camunda.bpm.spring.boot.starter.util.SpringBootProcessEnginePlugin.preInit(SpringBootProcessEnginePlugin.java:23) ~[camunda-bpm-spring-boot-starter-2.2.0.jar:2.2.0]
at org.camunda.bpm.engine.impl.cfg.CompositeProcessEnginePlugin.preInit(CompositeProcessEnginePlugin.java:90) ~[camunda-engine-7.8.0-alpha3.jar:7.8.0-alpha3]
at org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl.invokePreInit(ProcessEngineConfigurationImpl.java:857) ~[camunda-engine-7.8.0-alpha3.jar:7.8.0-alpha3]
at org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl.init(ProcessEngineConfigurationImpl.java:731) ~[camunda-engine-7.8.0-alpha3.jar:7.8.0-alpha3]
at org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl.buildProcessEngine(ProcessEngineConfigurationImpl.java:722) ~[camunda-engine-7.8.0-alpha3.jar:7.8.0-alpha3]
at org.camunda.bpm.engine.spring.SpringTransactionsProcessEngineConfiguration.buildProcessEngine(SpringTransactionsProcessEngineConfiguration.java:62) ~[camunda-engine-spring-7.8.0-alpha3.jar:7.8.0-alpha3]
at org.camunda.bpm.engine.spring.ProcessEngineFactoryBean.getObject(ProcessEngineFactoryBean.java:52) ~[camunda-engine-spring-7.8.0-alpha3.jar:7.8.0-alpha3]
at org.camunda.bpm.engine.spring.ProcessEngineFactoryBean.getObject(ProcessEngineFactoryBean.java:31) ~[camunda-engine-spring-7.8.0-alpha3.jar:7.8.0-alpha3]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]

I don’t think there is a matching Spring Boot Starter version yet. Then please check how it works with 7.7.0.

It results in same error with 7.7.0 version

Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964) ~[mysql-connector-java-5.1.40.jar:5.1.40]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897) ~[mysql-connector-java-5.1.40.jar:5.1.40]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886) ~[mysql-connector-java-5.1.40.jar:5.1.40]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860) ~[mysql-connector-java-5.1.40.jar:5.1.40]
at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1138) ~[mysql-connector-java-5.1.40.jar:5.1.40]
at sun.reflect.GeneratedMethodAccessor139.invoke(Unknown Source) ~[?:?]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_131]
at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:62) ~[mybatis-3.2.8.jar:3.2.8]
at com.sun.proxy.$Proxy120.execute(Unknown Source) ~[?:?]
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:44) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:69) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:48) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:105) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:71) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:152) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:141) ~[mybatis-3.2.8.jar:3.2.8]
at org.camunda.bpm.engine.impl.db.sql.DbSqlSession.executeInsertEntity(DbSqlSession.java:146) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.db.sql.DbSqlSession.insertEntity(DbSqlSession.java:138) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.db.AbstractPersistenceSession.executeDbOperation(AbstractPersistenceSession.java:41) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flushDbOperationManager(DbEntityManager.java:303) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager.flush(DbEntityManager.java:281) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:203) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.interceptor.CommandContext.close(CommandContext.java:132) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:113) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:42) ~[camunda-engine-spring-7.7.0.jar:7.7.0]
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.camunda.bpm.engine.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:40) ~[camunda-engine-spring-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.interceptor.ProcessApplicationContextInterceptor.execute(ProcessApplicationContextInterceptor.java:66) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariablesTyped(RuntimeServiceImpl.java:248) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariablesTyped(RuntimeServiceImpl.java:243) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariables(RuntimeServiceImpl.java:238) ~[camunda-engine-7.7.0.jar:7.7.0]
at org.camunda.bpm.engine.impl.RuntimeServiceImpl.getVariables(RuntimeServiceImpl.java:69) ~[camunda-engine-7.7.0.jar:7.7.0]

Hm, ok. Can you create a failing test case that reproduces the issue?

I’m using Camunda 7.5.0 and I am 99% sure I am impacted by this same bug.

I could not wrap my head around the multiple entries in my database that I saw today but after reading this topic it starts to make sense. All but the very last ge_bytearray entry is a loose reference that is not linked to any hi_varinst entry. The variable names have unixtime included, so they are clearly copied and not newly created by the front-end . (Also in that case, they would have a hi_varinst entry or at least the revision number should be 1 up).