Uploaded image for project: 'camunda BPM'
  1. camunda BPM
  2. CAM-14499

Process variables are deleted when concurrent execution appears

    XMLWordPrintable

Details

    • Bug Report
    • Resolution: Duplicate
    • L3 - Default
    • None
    • 7.15.0-alpha2, 7.16.0, 7.17.0-alpha5
    • engine

    Description

      Environment (Required on creation):

      • Spring Boot 2.6.4
      • Java 17
      • Camunda DB - MySQL

      dependencies
          - "org.camunda.bpm.springboot:camunda-bpm-spring-boot-starter:7.16.0"
          - "org.camunda.bpm.springboot:camunda-bpm-spring-boot-starter-webapp:7.16.0"
          - "org.camunda.bpm.springboot:camunda-bpm-spring-boot-starter-rest:7.16.0"
          - "com.sun.xml.bind:jaxb-impl:3.0.2"
          - "org.graalvm.js:js:22.0.0.2"
          - "org.graalvm.js:js-scriptengine:22.0.0.2"
          - "org.camunda.bpm.assert:camunda-bpm-assert:14.0.0"

      Description (Required on creation; please attach any relevant screenshots, stacktraces, log files, etc. to the ticket):

      Our team tried to upgrade from camunda 7.14.0 to 7.16.0 (sql patches also applied). After that our `tests` (unit and integration) `started to fail`, but when manually checking camunda behavior - it is ok. First version after 7.14.0 where tests started to fail is 7.15-alpha2. Tests are passing without problems in the same environment with camunda 7.14.0.

      Steps to reproduce (Required on creation):

      ## Unit Test 
      ### Configuration
      ```java
      package camunda.shared.configuration;import java.io.IOException;
      import java.util.List;
      import javax.sql.DataSource;
      import org.camunda.bpm.engine.ProcessEngineConfiguration;
      import org.camunda.bpm.engine.impl.cfg.CompositeProcessEnginePlugin;
      import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
      import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin;
      import org.camunda.bpm.engine.impl.cfg.SpringBeanFactoryProxyMap;
      import org.camunda.bpm.engine.impl.el.ExpressionManager;
      import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration;
      import org.camunda.bpm.extension.process_test_coverage.spring.SpringProcessWithCoverageEngineConfiguration;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.transaction.PlatformTransactionManager;@Configuration
      public class UnitTestsProcessEngineConfiguration {
        @Bean
        public ProcessEngineConfigurationImpl processEngineConfiguration(
            final List<ProcessEnginePlugin> processEnginePlugins,
            final ExpressionManager expressionManager,
            final PlatformTransactionManager transactionManager,
            final DataSource dataSource,
            final ApplicationContext applicationContext
        ) throws IOException {
          SpringProcessEngineConfiguration config =
              new SpringProcessWithCoverageEngineConfiguration();
          config.setExpressionManager(expressionManager);
          config.setTransactionManager(transactionManager);
          config.setDataSource(dataSource);
          config.setDatabaseSchemaUpdate("true");
          config.setHistory(ProcessEngineConfiguration.HISTORY_FULL);
          config.setJobExecutorActivate(false); // <---
          config.setProcessEnginePlugins(
              processEnginePlugins
          );    config.getProcessEnginePlugins().add(
              new CompositeProcessEnginePlugin(processEnginePlugins)
          );
          config.setBeans(new SpringBeanFactoryProxyMap(applicationContext));
          return config;  }
      }```
      
      Here is sample process and test for it:
      ![[DAV-2_POC_1.bpmn]]
      
      ```kotlin
          @Test
          @DeployProcess(["DAV-2_POC_1.bpmn"])
          fun `POC 1 - variables are deleted`() {
              val builder: ProcessInstantiationBuilder = this.processEngine.runtimeService
                      .createProcessInstanceByKey("DAV-2_POC_1")
              builder.setVariable("featureIssueId", 178825)
              builder.setVariable("implementationCategory", "category-value")
              builder.startBeforeActivity("Implement_feature")
              val processInstance: ProcessInstance = builder.execute();        
      // waiting for task to be resolved        
      BpmnAwareTests.assertThat(processInstance).isWaitingAt("Implement_feature")        
      val processExecution: Execution = this.processEngine.runtimeService
                      .createExecutionQuery()
                      .processInstanceId(processInstance.id)
                      .active()
                      .list()
                      .firstOrNull()!!       
      // process variables are there
              assertEquals(178825, getVariable(processExecution.id, "featureIssueId"))
              assertEquals("category-value", getVariable(processExecution.id, "implementationCategory"))
              assertNull(getVariable(processExecution.id, "implementationIssue"))        
      // triggering script task that will set `issueId`
              this.processEngine
      .runtimeService.createProcessInstanceModification(processInstance.id)
                      .startBeforeActivity("Set_issue_id")
                      .execute()        
      // `implementationIssue` is set by event `Implement_feature_issue_id_set` after `issueId` was set
              assertEquals(777, getVariable(processExecution.id, "implementationIssue"))        
      // !!! process variables are not there after event is executed !!!
              assertEquals(178825, getVariable(processExecution.id, "featureIssueId")) // assert fails
              assertEquals("category-value", getVariable(processExecution.id, "implementationCategory")) // assert fails
          }    fun getVariable(executionId: String, variableName: String): Any? {
              return this.processEngine.runtimeService.getVariable(executionId, variableName)
          }
      ```
      
      Output (last asserts): 
      ```
      Expected :178825
      Actual   :null
      
      ```
      ## Integration Test
      ### Configuration
      ```java
      package camunda.shared.configuration;import java.io.IOException;
      import java.util.List;
      import javax.sql.DataSource;
      import org.camunda.bpm.engine.ProcessEngineConfiguration;
      import org.camunda.bpm.engine.impl.cfg.CompositeProcessEnginePlugin;
      import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
      import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin;
      import org.camunda.bpm.engine.impl.cfg.SpringBeanFactoryProxyMap;
      import org.camunda.bpm.engine.impl.el.ExpressionManager;
      import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration;
      import org.camunda.bpm.extension.process_test_coverage.spring.SpringProcessWithCoverageEngineConfiguration;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.transaction.PlatformTransactionManager;@Configuration
      public class IntegrationTestsProcessEngineConfiguration {
        @Bean
        public ProcessEngineConfigurationImpl processEngineConfiguration(
            final List<ProcessEnginePlugin> processEnginePlugins,
            final ExpressionManager expressionManager,
            final PlatformTransactionManager transactionManager,
            final DataSource dataSource,
            final ApplicationContext applicationContext
        ) throws IOException {
          SpringProcessEngineConfiguration config =
              new SpringProcessWithCoverageEngineConfiguration();
          config.setExpressionManager(expressionManager);
          config.setTransactionManager(transactionManager);
          config.setDataSource(dataSource);
          config.setDatabaseSchemaUpdate("true");
          config.setHistory(ProcessEngineConfiguration.HISTORY_FULL);
          config.setJobExecutorActivate(true); // <---
          config.getProcessEnginePlugins().add(
              new CompositeProcessEnginePlugin(processEnginePlugins)
          );
          config.setBeans(new SpringBeanFactoryProxyMap(applicationContext));
          return config;  }
      }```Test is the same as above.
      Output is the same, variables are removed.
      

      Observed Behavior (Required on creation):

      Output (last asserts): 
      ```
      Expected :178825
      Actual   :null
      ```

      Process variables are erased.

      Expected behavior (Required on creation):

      Process variables must not be erased.

      Root Cause (Required on prioritization):

      camunda-bpm engine

      Solution Ideas (Optional):

      Hints (optional):

      ### The place variables are removed
      ExecutionEntity.java
      ```java
      ...
        protected void moveVariableTo(VariableInstanceEntity variable, ExecutionEntity other) {
          if (other.variableStore.containsKey(variable.getName())) {
            // this is executed when ExecutionEntity.replace(PvmExecutionImpl execution) where commant says: // on compaction, move all variables
            CoreVariableInstance existingInstance = other.variableStore.getVariable(variable.getName());
            existingInstance.setValue(variable.getTypedValue(false));
            invokeVariableLifecycleListenersUpdate(existingInstance, this);
            invokeVariableLifecycleListenersDelete( // <-- here VariableInstanceEntityPersistenceListener.delete()
                variable,
                this,
                Collections.singletonList(getVariablePersistenceListener()));
          }
          else {
            // this is executed when new concurrent execution is created 
            // scenario 2 in PvmExecutionImpl.createConcurrentExecution()
            other.variableStore.addVariable(variable);
          }
        }
      ...
      ```
      
      It seems like it is happening when there are `concurrent execution` takes place.
          1. Manual check:
            Started process via Cockpit:

      After 10 seconds - expected results (how it should be in tests)

          1. Modified verison of process with same (failing in tests) result

       

      It is happening when concurrent executions come into play, like message events, timers, boundary events etc...

      mgm-controller-panel

        This is the controller panel for Smart Panels app

        Attachments

          Issue Links

            Activity

              People

                tassilo.weidner Tassilo Weidner
                d.nikolaev Daniil Nikolaev
                Votes:
                1 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved:

                  Salesforce