4 Replies Latest reply on Oct 14, 2010 5:37 AM by misieq

    Problem terminating concurent executions that have active sub-processes [jBPM 4.3/4.4 + Oracle]

    misieq

      I have a process that contains a fork activity with two branches - one containing a sub-process and the other any type of node from which we can terminate the whole process directly. A simplified version for test purposes would be:

       

      {code:xml}

      <?xml version="1.0" encoding="UTF-8"?>

      <process name="p1"

          schemaLocation="http://jbpm.org/4.0/jpdl http://docs.jboss.org/jbpm/xsd/jpdl-4.0.xsd"

          xmlns="http://jbpm.org/4.0/jpdl">


          <start g="143,27,80,40" name="start">

              <transition g="-54,-22" name="to fork1" to="fork1" />

          </start>


          <fork g="143,117,48,48" name="fork1">

              <transition g="-38,-22" name="to p2" to="p2" />

              <transition g="34,-14" name="to state1" to="state1" />

          </fork>


          <state g="199,214,108,52" name="state1">

              <transition to="join1" />

              <transition g="-11,-21" name="end" to="end2" />

          </state>


          <sub-process g="18,227,92,52" name="p2" sub-process-key="p2">

              <transition to="join1" />

          </sub-process>


          <join g="141,334,48,48" name="join1">

              <transition to="end" />

          </join>


          <end-cancel g="405,217,92,102" name="end2" />

          <end g="141,446,80,40" name="end" />


      </process>

      {code}

       

      When I run the process and try to signal node 'state1' to end the whole process I get a constraint violation :

       

       

      {color:red}

      org.hibernate.exception.ConstraintViolationException: could not delete: [org.jbpm.pvm.internal.model.ExecutionImpl#10002]

          at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)

          at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)

          at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2569)

          at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2725)

          at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:97)

          at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)

          at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)

          at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)

          at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)

          at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)

          at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:996)

          at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1141)

          at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)

          at org.hibernate.impl.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:835)

          at org.jbpm.pvm.internal.hibernate.DbSessionImpl.findProcessInstanceByIdIgnoreSuspended(DbSessionImpl.java:211)

          at org.jbpm.pvm.internal.hibernate.DbSessionImpl.deleteProcessInstance(DbSessionImpl.java:251)

          at org.jbpm.pvm.internal.model.ExecutionImpl.end(ExecutionImpl.java:382)

          at org.jbpm.jpdl.internal.activity.EndActivity.execute(EndActivity.java:82)

          at org.jbpm.jpdl.internal.activity.EndActivity.execute(EndActivity.java:45)

          at org.jbpm.pvm.internal.model.op.ExecuteActivity.perform(ExecuteActivity.java:60)

          at org.jbpm.pvm.internal.model.ExecutionImpl.performAtomicOperationSync(ExecutionImpl.java:656)

          at org.jbpm.pvm.internal.model.ExecutionImpl.performAtomicOperation(ExecutionImpl.java:616)

          at org.jbpm.pvm.internal.model.ExecutionImpl.signal(ExecutionImpl.java:417)

          at org.jbpm.pvm.internal.cmd.SignalCmd.execute(SignalCmd.java:61)

          at org.jbpm.pvm.internal.cmd.SignalCmd.execute(SignalCmd.java:35)

          at org.jbpm.pvm.internal.svc.DefaultCommandService.execute(DefaultCommandService.java:42)

          at org.jbpm.pvm.internal.tx.SpringCommandCallback.doInTransaction(SpringCommandCallback.java:45)

          at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:128)

          at org.jbpm.pvm.internal.tx.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:55)

          at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.executeInNewEnvironment(EnvironmentInterceptor.java:53)

          at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)

          at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:55)

          at org.jbpm.pvm.internal.svc.ExecutionServiceImpl.signalExecutionById(ExecutionServiceImpl.java:88)

          at org.jbpm.test.SubprocessTest.testEndWithActiveSubprocesses(SubprocessTest.java:25)

          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

          at java.lang.reflect.Method.invoke(Method.java:597)

          at org.springframework.test.context.junit4.SpringTestMethod.invoke(SpringTestMethod.java:160)

          at org.springframework.test.context.junit4.SpringMethodRoadie.runTestMethod(SpringMethodRoadie.java:233)

          at org.springframework.test.context.junit4.SpringMethodRoadie$RunBeforesThenTestThenAfters.run(SpringMethodRoadie.java:333)

          at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:217)

          at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:197)

          at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:143)

          at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:160)

          at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)

          at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)

          at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)

          at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)

          at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)

          at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)

          at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)

          at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)

          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

      Caused  by: java.sql.SQLException: ORA-02292: violation de contrainte  (BDOOA.FK_EXEC_SUPEREXEC) d'intégrité - enregistrement fils existant

          at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)

          at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)

          at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)

          at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:745)

          at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:216)

          at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:966)

          at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1170)

          at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3339)

          at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3423)

          at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2551)

          ... 54 more

      {color}

       

      I investigated the problem and I found out that it is due to the fact that we never try to terminate an existing sub-process from within the ExecutionImpl.end() method. It causes a delete of the parent execution row although it is still referenced by SUPEREXEC_ column of the sub-process.

       

      I created a patch that works and that consists on adding the following code to ExecutionImpl.end(String state) (my code in the middle paragraph):

       

       

      {code}

         // end all child executions

         // making a copy of the executions to prevent ConcurrentMoidificationException

          List<ExecutionImpl> executionsToEnd = new ArrayList<ExecutionImpl>(executions);

          for (ExecutionImpl child: executionsToEnd) {

            child.end(state);

          }


          // terminates the sub-process if it exists

          if(subProcessInstance != null) {

          // to avoid the return signal (see superProcessExecution.signal() in the end(String state) method)

              subProcessInstance.setSuperProcessExecution(null);

              subProcessInstance.end(state);

          }


          setState(state);

      {code}

       

      I don't know if it is the right approach but it works pretty much fine. Do you think it's the right way to do it?

      I created a jira where I join the patch and a test module.

        • 1. Re: Problem terminating concurent executions that have active sub-processes [jBPM 4.3/4.4 + Oracle]
          saig0

          Hi Michal!

           

          I have a similar process like you and your patch works great!

           

          But when I tried to run a more complex process, I got the ConstraintViolationException again.

          I took your processes p1 and p2 and added a process p3:

           

          <?xml version="1.0" encoding="UTF-8"?>
          <process name="p3"
              schemaLocation="http://jbpm.org/4.0/jpdl http://docs.jboss.org/jbpm/xsd/jpdl-4.0.xsd"
              xmlns="http://jbpm.org/4.0/jpdl">
              <start g="143,27,80,40" name="start">
                  <transition g="-54,-22" name="to fork1" to="fork1" />
              </start>
              <fork g="143,117,48,48" name="fork1">
                  <transition g="-38,-22" name="to p2" to="p2" />
                  <transition g="34,-14" name="to p2 (2)" to="p2 (2)" />
              </fork>
          
              <sub-process g="18,227,92,52" name="p2" sub-process-key="p2">
                  <transition to="join1" />
              </sub-process>
               <sub-process g="18,227,92,52" name="p2 (2)" sub-process-key="p2 (2)">
                  <transition to="join1" />
              </sub-process>
          
              <join g="141,334,48,48" name="join1">
                  <transition to="end" />
              </join>
              <end g="141,446,80,40" name="end" />
          </process>
          

           

          The process p3 just call two concurrent subprocesses to p2. And I changed the subprocess in p1 from p2 to p3.

          So process p1 calls p3 that calls p2 two times in concurrent patchs.  p1 -> p3 -> (2x) p2

           

          The ConstraintViolationException throws after ending the first p2 execution.

          Do you know why?

          • 2. Re: Problem terminating concurent executions that have active sub-processes [jBPM 4.3/4.4 + Oracle]
            misieq

            Hi,

             

            I will check it out this afternoon. I found that the patch is not perfect because it messes up the join. But I have a solution that should work well. Will publish after work.

             

            Thanks for sharing!

            • 3. Re: Problem terminating concurent executions that have active sub-processes [jBPM 4.3/4.4 + Oracle]
              saig0

              Hi,

               

              I tried a bit with your changes to resolve my problem and it seems that I found a fix.

              I suspend the sub process instance instead of end it:

               

               // terminates the sub-process if it exists
               if (subProcessInstance != null)
               {
                   // to avoid the return signal (see superProcessExecution.signal() in
                   // the end(String state) method)
                   subProcessInstance.setSuperProcessExecution(null);
                   subProcessInstance.suspend();
               }

               

              Can you verify my changes?

              • 4. Re: Problem terminating concurent executions that have active sub-processes [jBPM 4.3/4.4 + Oracle]
                misieq

                Hey,

                 

                sorry for late response. I did some more tests with the patch I proposed and I found out that the problem is not trivial. I'm not even sure if it can be fixed. The problem is that when you call

                subProcessInstance.setSuperProcessExecution(null);
                

                 

                you break the link between child and parent process. And this link is necessary in SubProcessActivity to extract return variables.

                 

                Also when you suspend your subprocess you don't delete it from the database which is a big problem of version 4.3 in general (I think it has been fixed in 4.4).

                 

                Currently I'm testing a solution with subprocess deletion in SubProcessActivity but it still creates some problems.

                 

                I'll keep you informed.

                 

                I would be cool to have an opinion from someone from the development team on that. Anyone?