KingbaseES database adaptation Activiti7 didn’t put process definition problem handling process

1. Introduction to Activiti

Activiti is a lightweight java open source BPMN 2 workflow engine. It is currently upgraded to 7.x and supports integration with springboot2.x.

2. Project environment

Spring Boot version 2.2.5

Activiti version 7.1.x

Source database: MySQL 5.7

Target database: KinbgaseES V008R006C007B0024

JDBC driver: JDBC driver in Postgre form, postgresql-42.2.9.jar

3. Error messages

This project is adapted to migrate MySQL database data to the KingbaseES database. After the data migration is completed, Activiti starts and reports an error.

Activiti startup error message:

org.activiti.engine.ActivitiException: deployment '01048b5e-79e5-11ed-a2ea-ba4c05fac664' didn't put process definition '010accf0-79e5-11ed-a2ea-ba4c05fac664' in the cache
    at org.activiti.engine.impl.persistence.deploy.DeploymentManager.resolveProcessDefinition(DeploymentManager.java:127)
    at org.activiti.engine.impl.persistence.deploy.DeploymentManager.findDeployedProcessDefinitionById(DeploymentManager.java:76)
    at org.activiti.engine.impl.util.ProcessDefinitionUtil.getBpmnModel(ProcessDefinitionUtil.java:65)
    at org.activiti.engine.impl.cmd.GetBpmnModelCmd.execute(GetBpmnModelCmd.java:41)
    at org.activiti.engine.impl.cmd.GetBpmnModelCmd.execute(GetBpmnModelCmd.java:26)
    at org.activiti.engine.impl.interceptor.CommandInvoker$1.run(CommandInvoker.java:37)
    at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:78)
    at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:57)
    at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:42)
    at org.activiti.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:48)
    at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:59)
    at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:47)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
    at org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:45)
    at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:29)
    at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:44)
    at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:39)
    at org.activiti.engine.impl.RepositoryServiceImpl.getBpmnModel(RepositoryServiceImpl.java:142)
    at org.activiti.runtime.api.model.impl.APIProcessDefinitionConverter.from(APIProcessDefinitionConverter.java:43)
    at org.activiti.runtime.api.model.impl.APIProcessDefinitionConverter.from(APIProcessDefinitionConverter.java:26)
    at org.activiti.runtime.api.model.impl.ListConverter.from(ListConverter.java:28)
    at org.activiti.spring.ProcessDeployedEventProducer.doStart(ProcessDeployedEventProducer.java:55)
    at org.activiti.spring.AbstractActivitiSmartLifeCycle.start(AbstractActivitiSmartLifeCycle.java:68)
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182)
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53)
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360)
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158)
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:894)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
    at com.cityOperation.ComDjldPlatformApplication.main(ComDjldPlatformApplication.java:39)

Four. Problem Cause Analysis

4.1. This error will occur when cachedProcessDefinition==null is found by checking the Activiti source code.

/**
 * Resolving the process definition will fetch the BPMN 2.0, parse it and store the {@link BpmnModel} in memory.
 */
public ProcessDefinitionCacheEntry resolveProcessDefinition(ProcessDefinition processDefinition) {
 String processDefinitionId = processDefinition.getId();
 String deploymentId = processDefinition.getDeploymentId();
 ProcessDefinitionCacheEntry cachedProcessDefinition = processDefinitionCache.get(processDefinitionId);
 if (cachedProcessDefinition == null) {
  CommandContext commandContext = Context.getCommandContext();
  if (commandContext.getProcessEngineConfiguration().isActiviti5CompatibilityEnabled() & amp; & amp;
    Activiti5Util.isActiviti5ProcessDefinition(Context.getCommandContext(), processDefinition)) {

   return Activiti5Util.getActiviti5CompatibilityHandler().resolveProcessDefinition(processDefinition);
  }

  DeploymentEntity deployment = deploymentEntityManager.findById(deploymentId);
  deployment.setNew(false);
  deploy(deployment, null);
  cachedProcessDefinition = processDefinitionCache.get(processDefinitionId);
  if (cachedProcessDefinition == null) {
   throw new ActivitiException("deployment '" + deploymentId + "' didn't put process definition '" + processDefinitionId + "' in the cache");
  }
 }
 return cachedProcessDefinition;
}

The function of the Activiti framework DeploymentManager.resolveProcessDefinition method is to parse out the corresponding process definition object and BPMN model object based on the ID or KEY of the process definition. This method will first search from the cache. If it is not found, it will call the deploy method of the Deployer object to deploy the process definition and put the parsed object into the cache. This method is mainly used to create a process instance based on the information defined by the process when executing the process instance.

4.2. Query the process definition table in the database

Use the following sql to query:

--$1 is replaced with the DEPLOYMENT_ID_ that reported the error
select * from ACT_RE_PROCDEF where DEPLOYMENT_ID_ = $1
--The replaced sql is
select * from ACT_RE_PROCDEF where DEPLOYMENT_ID_ = '01048b5e-79e5-11ed-a2ea-ba4c05fac664'

If there is data in the ACT_RE_PROCDEF process definition table, you need to query the database log to find out the program query sql statement:

--Database log
2023-05-25 19:47:21 CST [10136]: [19-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248DETAIL: parameters: $1 = '01048b5e-79e5- 11ed-a2ea-ba4c05fac664'
2023-05-25 19:47:21 CST [10136]: [20-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: execute <unnamed>: select * from ACT_GE_BYTEARRAY where DEPLOYMENT_ID_ = $1 order by NAME_ asc
2023-05-25 19:47:21 CST [10136]: [21-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248DETAIL: parameters: $1 = '01048b5e-79e5- 11ed-a2ea-ba4c05fac664'
2023-05-25 19:47:21 CST [10136]: [22-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: execute <unnamed>: select *
        from ACT_RE_PROCDEF
        where DEPLOYMENT_ID_ = $1
          and KEY_ = $2
          and (TENANT_ID_ = '' or TENANT_ID_ is null)
2023-05-25 19:47:21 CST [10136]: [23-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248DETAIL: parameters: $1 = '01048b5e-79e5- 11ed-a2ea-ba4c05fac664', $2 = 'yaotangzhuanxiangkaopingliucheng2'
2023-05-25 19:47:21 CST [10136]: [24-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: execute S_2: ROLLBACK
2023-05-25 19:47:21 CST [10131]: [22-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: disconnection: session time: 0:00: 30.978 user=system database=ygf host=10.0.8.248 port=7005
2023-05-25 19:47:21 CST [10134]: [19-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: disconnection: session time: 0:00: 27.940 user=system database=ygf host=10.0.8.248 port=7008
2023-05-25 19:47:21 CST [10135]: [11-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: disconnection: session time: 0:00: 27.890 user=system database=ygf host=10.0.8.248 port=7009
2023-05-25 19:47:21 CST [10136]: [25-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: disconnection: session time: 0:00: 27.839 user=system database=ygf host=10.0.8.248 port=7010
2023-05-25 19:47:21 CST [10137]: [7-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248LOG: disconnection: session time: 0:00: 27.804 user=system database=ygf host=10.0.8.248 port=7011

--Program query sql
select *
        from ACT_RE_PROCDEF
        where DEPLOYMENT_ID_ = $1
          and KEY_ = $2
          and (TENANT_ID_ = '' or TENANT_ID_ is null)
2023-05-25 19:47:21 CST [10136]: [23-1] user=system,db=ygf,app=PostgreSQL JDBC Driver,client=10.0.8.248DETAIL: parameters: $1 = '01048b5e-79e5- 11ed-a2ea-ba4c05fac664', $2 = 'yaotangzhuanxiangkaopingliucheng2'

Use the program query sql found in the database log to query the database and find that no data is returned. Through positioning, it is found that it is due to the condition TENANT_ID_ = ” or TENANT_ID_ is null.

4.3. Query database parameter configuration

show ora_input_emptystr_isnull;
 ORA_INPUT_EMPTYSTR_ISNULL
--------------------------
 on
(1 row)

--This parameter is used to process parameters when inputting an empty string:
--on indicates that the input empty string will be processed as a null value, and off indicates that it will not be processed

In the KingbaseES database, ora_input_emptystr_isnull=on scenario: empty string ”use =” The database will process the input empty string as a null value. When used as a null value, the data cannot be matched, and in the database, the TENANT_ID_ field data The value is ”, and the query process definition table did not return when the program started, resulting in an exception.

Five, solutions

Modify the database ora_input_emptystr_isnull parameter to off.