AnsweredAssumed Answered

Process started in Activiti Explorer results in integrity constraint violation, but starting programmatically is OK

Question asked by slehman on May 24, 2013
Latest reply on May 28, 2013 by jbarrez
I'm making the case for Activiti at my company and have been getting my feet wet by trying to figure out how to work with some long-running asynchronous processes.   The receive task looks like the way to go, but I've already run into a problem.

My process is simply  start -> receive -> end.   When I start a process programmatically, I can signal the execution, and things work as expected.  But when I start the process using Activiti Explorer (running as a standalone .war), after signaling the execution, I see an exception:

SEVERE: Error while closing command context
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database.  Cause: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "ACT_FK_IDL_PROCINST: PUBLIC.ACT_RU_IDENTITYLINK FOREIGN KEY(PROC_INST_ID_) REFERENCES PUBLIC.ACT_RU_EXECUTION(ID_) ('3070')"; SQL statement:
delete from ACT_RU_EXECUTION where ID_ = ? [23503-171]
   at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
   at org.h2.message.DbException.get(DbException.java:169)
   at org.h2.message.DbException.get(DbException.java:146)
   at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:414)
   at org.h2.constraint.ConstraintReferential.checkRowRefTable(ConstraintReferential.java:431)
   at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:307)
   at org.h2.table.Table.fireConstraints(Table.java:873)
   at org.h2.table.Table.fireAfterRow(Table.java:890)
   at org.h2.command.dml.Delete.update(Delete.java:99)
   at org.h2.command.CommandContainer.update(CommandContainer.java:75)
   at org.h2.command.Command.executeUpdate(Command.java:230)
   at org.h2.server.TcpServerThread.process(TcpServerThread.java:334)
   at org.h2.server.TcpServerThread.run(TcpServerThread.java:150)
   at java.lang.Thread.run(Unknown Source)


I can see the entries in ACT_RU_IDENTITYLINK that are created only when Explorer is used to start the process, but I am at a loss for what I need to do to make this work.

My process definition is:

<?xml version="1.0" encoding="UTF-8" ?>
<definitions id="definitions"
             targetNamespace="http://activiti.org/bpmn20"
             xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:activiti="http://activiti.org/bpmn">
 
  <process id="myVacationRequest" name="My Vacation request">
    <startEvent id="request" >
    </startEvent>
    <sequenceFlow id="flow1" sourceRef="request" targetRef="wait2" />
    <receiveTask id="wait2" name="wait"/>
    <sequenceFlow id="flow2a" sourceRef="wait2" targetRef="theEnd1" />
    <endEvent id="theEnd1" />
  </process>
</definitions>

The code I'm using is:

      ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
      if (processEngine == null) {
         log.error("Could not start Activiti Engine");
      }
      else {
         RepositoryService repositoryService = processEngine.getRepositoryService();
         repositoryService.createDeployment()
           .addClasspathResource("VacationRequest.bpmn20.xml")
           .deploy();
              
         log.info("Number of process definitions: " + repositoryService.createProcessDefinitionQuery().count());           
          
         // This process will complete as expected
          String procId = processEngine.getRuntimeService().startProcessInstanceByKey("myVacationRequest").getId();

         
          // Start a process in Activiti Explorer - it will result in an exception at the end of the process
          try {
            Thread.sleep(30000);
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }

          // Lookup executions in our wait activity, and signal them to advance
          RuntimeService rs = processEngine.getRuntimeService();
         List<Execution> executions = rs.createExecutionQuery().processDefinitionKey("myVacationRequest").activityId("wait2").list();
         
         for (Execution execution : executions) {
            log.info("Found execution " + execution.getId());
            try {
               rs.signal(execution.getId());
            } catch (RuntimeException e) {
               System.out.println(e.getMessage());
            }
         }
      }


Is there some other key step to using the Receive task that I'm missing?

Thanks,

Scott

Outcomes