11 Replies Latest reply on Jan 19, 2010 12:41 PM by lamj1

    How to terminate a forked process

    lamj1

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

       

      <process name="ForkSubProcess" xmlns="http://jbpm.org/4.0/jpdl">

       

      <start g="22,69,80,40">

        <transition to="fork"/>

      </start>

       

      <fork g="99,68,80,40" name="fork">

         <on continue="exclusive" event="end"/>

          <transition g="123,45:" to="Processing"/>

          <transition g="124,163:" to="PublishDocument"/>

      </fork>

       

       

      <task assignee="testUser" g="186,134,121,58" name="Processing">

         <transition g="373,162:-53,-21" name="to join" to="join"/>

      </task>

       

      <task assignee="testUser" g="186,134,121,58" name="PublishDocument">

         <transition g="373,162:-53,-21" name="to join" to="join"/>

      </task>

       

        <join g="411,136,80,40" name="join">

          <transition to="wait"/>

        </join>

       

        <state g="575,137,80,40" name="wait"> 

         <transition to="end"/>

        </state>

       

        <end g="725,131,48,48" name="end"/>

       

      </process>

       

       

       

      Java code:

        ProcessInstance instance = executionService.startProcessInstanceByKey("ForkSubProcess");

       

        Now if you look at the the JBPM4_EXECUTION table, there are three processes listed

       

      39 pvm 3 join ForkSubProcess-1 0 ForkSubProcess.38.39 inactive-join 0 46 38 38 0

      42 pvm 2 PublishDocument ForkSubProcess-1 0 ForkSubProcess.38.42 active-concurrent 0 50 38 38 1

      38 pvm 1 ForkSubProcess-1 0 ForkSubProcess.38 inactive-concurrent-root 0 38

       

       

         ....... I obtain a processID of a 'active-concurrent' process and attempt to end it.

       

        executionService.endProcessInstance(processID, "active");

       

      I get an exception

      ### EXCEPTION ###########################################

      20:13:01,757 INF | [DefaultCommandService] exception while executing command org.jbpm.pvm.internal.cmd.EndProcessInstance@a8c871

      java.lang.NullPointerException

      at org.jbpm.pvm.internal.cmd.EndProcessInstance.execute(EndProcessInstance.java:49)

       

      How can i gracefully end a forked process? without having to complete all the tasks.

        • 1. Re: How to terminate a forked process
          koen.aers

          Hi,

           

          Can you also post a JUnit test that demonstrates this problem?

           

          Cheers,

          Koen

          • 2. Re: How to terminate a forked process
            lamj1
            In fact, my code is somewhat irrelevant. It is more like how to terminate a forked process while it is still active? without causing exception and ensure the database entities are cleaned up gracefully.
            Junit code: 
            public void testForking()
              {
            ProcessInstance processInstance = workflowManager.startProcess("ForkSubProcess");
            String pid = processInstance.getId();
            //sleep to allow fork to create task before querying it
            try {Thread.sleep(2000);} catch(Exception e){}
            //verify that there are two outstanding tasks assign to testUser
            List<Task> taskList = taskService.findPersonalTasks("testUser");
            assertEquals(2, taskList.size());
            //attempt to ends all processes, while they are still active
            workflowManager.endAll();
            }
            public void endAll()
            {
            ProcessInstanceQuery query = executionService.createProcessInstanceQuery();
            List<ProcessInstance> listPI = query.list();
            for(ProcessInstance processInstance : listPI)
            {
            //using execution service to end
            //1. cause a child record found error - if this is the parent process
            //2. cause a null pointer exception - if this is the forked process
            // For the second case, I traced the code and found out that endProcessInstance method
            // query for the processInstanceid with a where clause parents == null
            //   <query name="findProcessInstanceById">
            //     <![CDATA[
            //      select processInstance
            //      from org.jbpm.pvm.internal.model.ExecutionImpl as processInstance
            //      where processInstance.id = :processInstanceId
            //        and processInstance.parent is null
            //        and processInstance.state != 'suspended'
            //     ]]>
            //   </query>
            executionService.endProcessInstance(processInstance.getId(), "active");
            //OR
            //i also tried this - unit test quit after this. Nothing was done
            ((ExecutionImpl) processInstance).end();
            }
            }
            • 3. Re: How to terminate a forked process
              kukeltje

              There is one basic assumption wrong in your example. There are no subprocesses!. So the name, terminology and api that are used are wrong. Yes, there are child executions (as the table is called) but a (sub)process is an execution, but an execution does not need to be a process (hence the 'isProcessInstance() method on Execution). So trying to end all these processes in a loop won't work since there only is one.

               

              Getting all executions and ending them should work.

              • 4. Re: How to terminate a forked process
                kukeltje

                kukeltje wrote:

                 

                Getting all executions and ending them should work.

                Yet https://jira.jboss.org/jira/browse/JBPM-2581 might be related

                • 5. Re: How to terminate a forked process
                  lamj1

                  Using the same jpdl file above

                   

                  I run the following unitTest

                  1) Is this the correct way of ending a forked execution?

                  2) How to resolve the execption?

                   

                  My unit test set up is pretty standard

                   

                  protected void setUp() throws Exception {

                      super.setUp();    

                      //add user to database

                      identityService.createUser("testUser", "testUser", "testUser", "testUser@ssoa.com");

                   

                      workflowManager = new WorkflowManager();

                   

                   

                      deploymentFork = repositoryService.createDeployment()

                      .addResourceFromClasspath("test/ssoa/jbpm/manager/ForkSubProcess.jpdl.xml").deploy();

                    }

                  public void testForking()

                  {

                         ProcessInstance processInstance = workflowManager.startProcess("ForkSubProcess");

                         String pid = processInstance.getId();

                   

                        Execution mainExe = executionService.findExecutionById(pid);

                   

                        ((ExecutionImpl)mainExe).end();    <--- line 99 Exception here

                  }

                   

                   

                   

                   

                  09:48:00,642 SEV | [BaseJbpmTestCase]

                  ### EXCEPTION ###########################################

                  09:48:00,642 SEV | [BaseJbpmTestCase] TEST THROWS EXCEPTION: no environment to get org.jbpm.pvm.internal.session.RepositorySession

                  org.jbpm.api.JbpmException: no environment to get org.jbpm.pvm.internal.session.RepositorySession

                  at org.jbpm.pvm.internal.env.EnvironmentImpl.getFromCurrent(EnvironmentImpl.java:197)

                  at org.jbpm.pvm.internal.env.EnvironmentImpl.getFromCurrent(EnvironmentImpl.java:190)

                  at org.jbpm.pvm.internal.model.ExecutionImpl.getProcessDefinition(ExecutionImpl.java:1120)

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

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

                  at test.ssoa.jbpm.manager.WorkflowManagerTest.testForking(WorkflowManagerTest.java:99)

                   

                   

                  1) How would I be able to get all executions? executionService doesn't provide such interface.

                  kukeltje wrote:

                   

                  Getting all executions and ending them should work.

                  Thank you

                  • 6. Re: How to terminate a forked process
                    kukeltje

                    It's not a unit test, but part of a unittest. Not something that we can run. Besides what is in workflowmanager? Could be lots of things wrong in there that we cannot see. So please make a real, full unittest with embedded process.

                     

                    Regarding the second quesition (or rather the third), have a look at the api and see what methods you have on Execution, you'd be surprised that there is one to get childexecutions...

                     

                    Oh, and **Impl classes/casts should normally not be needed.... Use the services to end things... See the docs for this.

                    • 7. Re: How to terminate a forked process
                      lamj1
                      These two files below are also attached
                      Summarize Objective:
                      1) Terminate a parent process that has forked child processes while it is still active
                      2) Ensure all child execution are also gracefully ended.
                      3) Any related tasks, and all executions are cleared out from JBPM4_TASK and JPBM4_EXECUTION tables
                      JPDL
                      <?xml version="1.0" encoding="UTF-8"?>
                      <process name="ForkProcess" xmlns="http://jbpm.org/4.0/jpdl">
                      <start g="22,69,80,40">
                        <transition to="fork"/>
                      </start>
                      <fork g="99,68,80,40" name="fork">
                         <on continue="exclusive" event="end"/>
                          <transition g="123,45:" to="Processing"/>
                          <transition g="124,163:" to="PublishDocument"/>
                      </fork>
                      <task assignee="testUser" g="215,18,121,58" name="Processing">
                         <transition g="440,105:-54,-53" name="to join" to="join"/>
                      </task> 
                       
                      <state g="204,138,121,58" name="PublishDocument">
                         <transition g="373,162:-53,-21" name="to join" to="join"/>
                      </state>
                        <join g="443,124,80,40" name="join">
                          <transition to="wait"/>
                        </join>
                        <state g="575,137,80,40" name="wait"> 
                         <transition to="end"/>
                        </state>
                       
                        <end g="725,131,48,48" name="end"/>
                      </process>
                      UnitTest code
                      package test.ssoa.jbpm.manager;
                      import org.jbpm.api.Execution;
                      import org.jbpm.api.ProcessInstance;
                      import org.jbpm.pvm.internal.model.ExecutionImpl;
                      import org.jbpm.test.JbpmTestCase;
                      public class ForkTest extends JbpmTestCase {
                        protected String deploymentFork;
                        protected void setUp() throws Exception {
                          super.setUp();
                        
                          //add user to database
                          identityService.createUser("testUser", "testUser", "testUser", "testUser@test.com");
                        
                          deploymentFork = repositoryService.createDeployment()
                          .addResourceFromClasspath("test/ssoa/jbpm/manager/ForkProcess.jpdl.xml").deploy();   
                        
                        }
                        protected void tearDown() throws Exception {
                      //workflowManager.endAll();
                      identityService.deleteUser("testUser");
                      repositoryService.deleteDeploymentCascade(deploymentFork);
                      super.tearDown();  
                        }
                        public void testForking()
                        {
                        ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForkSubProcess");
                        String pid = processInstance.getId();
                        Execution mainExe = executionService.findExecutionById(pid);
                      ((ExecutionImpl)mainExe).end(); //exception here
                        }
                      }
                      Error trace
                      16:31:14,453 SEV | [BaseJbpmTestCase]
                      ### EXCEPTION ###########################################
                      16:31:14,454 SEV | [BaseJbpmTestCase] TEST THROWS EXCEPTION: no environment to get org.jbpm.pvm.internal.session.RepositorySession
                      org.jbpm.api.JbpmException: no environment to get org.jbpm.pvm.internal.session.RepositorySession
                      at org.jbpm.pvm.internal.env.EnvironmentImpl.getFromCurrent(EnvironmentImpl.java:197)
                      at org.jbpm.pvm.internal.env.EnvironmentImpl.getFromCurrent(EnvironmentImpl.java:190)
                      at org.jbpm.pvm.internal.model.ExecutionImpl.getProcessDefinition(ExecutionImpl.java:1120)
                      at org.jbpm.pvm.internal.model.ExecutionImpl.end(ExecutionImpl.java:373)
                      at org.jbpm.pvm.internal.model.ExecutionImpl.end(ExecutionImpl.java:325)
                      at test.ssoa.jbpm.manager.ForkTest.testForking(ForkTest.java:36)
                      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                      at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
                      at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
                      at java.lang.reflect.Method.invoke(Unknown Source)
                      at junit.framework.TestCase.runTest(TestCase.java:164)
                      at org.jbpm.test.BaseJbpmTestCase.runTest(BaseJbpmTestCase.java:80)
                      at junit.framework.TestCase.runBare(TestCase.java:130)
                      at junit.framework.TestResult$1.protect(TestResult.java:106)
                      at junit.framework.TestResult.runProtected(TestResult.java:124)
                      at junit.framework.TestResult.run(TestResult.java:109)
                      at junit.framework.TestCase.run(TestCase.java:120)
                      at junit.framework.TestSuite.runTest(TestSuite.java:230)
                      at junit.framework.TestSuite.run(TestSuite.java:225)
                      at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
                      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)
                      ### EXCEPTION ###########################################
                      • 8. Re: How to terminate a forked process
                        kukeltje
                        Try  2, 1 instead of 1, 2. Cancelling the tasks if an execution is cancelled is under discussion.
                        • 9. Re: How to terminate a forked process
                          lamj1

                          So i modify the testForking method to attempt to terminate all child executions first as follow

                           

                          public void testForking()

                            {

                                 ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForkProcess");

                                 String pid = processInstance.getId();

                           

                                 Execution mainExe = executionService.findExecutionById(pid);  

                           

                           

                                 List<Execution> exeList = (List<Execution>) mainExe.getExecutions();

                           

                                 for(Execution exe : exeList)

                                 {

                                      System.out.println(exe.getId());

                                      ((ExecutionImpl) exe).end();

                                 } 

                                ((ExecutionImpl)mainExe).end(); //exception here

                          }

                           

                          Two child executions were found, but after one is ended, the for loop quits. The same exception occurs when mainExe is ended.

                          • 10. Re: How to terminate a forked process
                            kukeltje
                            But I also mentioned NOT to invoke methods on executionds, but use SERVICES.... please fix that first.
                            • 11. Re: How to terminate a forked process
                              lamj1
                              public void testForking()
                                {
                                ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForkProcess");
                                String pid = processInstance.getId();
                                Execution mainExe = executionService.findExecutionById(pid);  
                                executionService.endProcessInstance(mainExe.getId(), "active");
                                }
                              Just make sure endProcessInstance is called for the top parent process. Attempting to end a child process can cause an exception.
                              Also any of your child process contain a subprocess, the subprocess also must to be terminated prior to this.