Uploaded image for project: 'jBPM'
  1. jBPM
  2. JBPM-9341

Detached WorkItemInfo entities error when aborting cases containing active/running subcases

    Details

      Description

      Having a running case which at the same time contains a running sub-case (containing at least one task), if you try to cancel parent case, following exception is thrown:

      org.jbpm.services.api.ProcessInstanceNotFoundException: Process instance with id 1 was not found 
      at org.jbpm.kie.services.impl.ProcessServiceImpl.abortProcessInstance(ProcessServiceImpl.java:224) 
      at org.jbpm.kie.services.impl.ProcessServiceImpl.abortProcessInstance(ProcessServiceImpl.java:206) 
      at org.jbpm.kie.services.impl.ProcessServiceImpl.lambda$abortProcessInstances$0(ProcessServiceImpl.java:234) 
      at java.util.ArrayList.forEach(ArrayList.java:1257) 
      at org.jbpm.kie.services.impl.ProcessServiceImpl.abortProcessInstances(ProcessServiceImpl.java:232) 
      at org.jbpm.casemgmt.impl.command.CancelCaseCommand.execute(CancelCaseCommand.java:90) 
      at org.jbpm.casemgmt.impl.command.CancelCaseCommand.execute(CancelCaseCommand.java:45) 
      at org.drools.core.fluent.impl.PseudoClockRunner.executeBatch(PseudoClockRunner.java:102) 
      at org.drools.core.fluent.impl.PseudoClockRunner.executeBatches(PseudoClockRunner.java:69) 
      at org.drools.core.fluent.impl.PseudoClockRunner.execute(PseudoClockRunner.java:61) 
      at org.drools.core.fluent.impl.PseudoClockRunner.execute(PseudoClockRunner.java:39) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:605) 
      at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:565) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.internalExecute(OptimisticLockRetryInterceptor.java:102) 
      at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:83) 
      at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:44) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:73) 
      at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:45) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.internalExecute(ExecutionErrorHandlerInterceptor.java:66) at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:52) 
      at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:29) 
      at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:400) 
      at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:68) 
      at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:37) 
      at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:41) 
      at org.drools.core.command.impl.CommandBasedStatefulKnowledgeSession.execute(CommandBasedStatefulKnowledgeSession.java:537) 
      at org.jbpm.kie.services.impl.ProcessServiceImpl.execute(ProcessServiceImpl.java:740) 
      at org.jbpm.casemgmt.impl.CaseServiceImpl.cancelCase(CaseServiceImpl.java:273) at org.jbpm.casemgmt.impl.SubCaseServiceImplTest.testStartCaseWithDynamicSubCaseAbortMainCase(SubCaseServiceImplTest.java:216) 
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
      at java.lang.reflect.Method.invoke(Method.java:498) 
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) 
      at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) 
      at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) 
      at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
      
      Caused by: java.lang.IllegalArgumentException: Removing a detached instance org.drools.persistence.info.WorkItemInfo#1 
      at org.hibernate.event.internal.DefaultDeleteEventListener.disallowDeletionOfDetached(DefaultDeleteEventListener.java:196) 
      at org.hibernate.event.internal.DefaultDeleteEventListener.performDetachedEntityDeletionCheck(DefaultDeleteEventListener.java:184) at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:105) 
      at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:72) 
      at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:1015) 
      at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:951) 
      at org.hibernate.internal.SessionImpl.remove(SessionImpl.java:3461) 
      at org.drools.persistence.jpa.JpaPersistenceContext.remove(JpaPersistenceContext.java:142) 
      at org.drools.persistence.jpa.processinstance.JPAWorkItemManager.internalAbortWorkItem(JPAWorkItemManager.java:131) 
      at org.jbpm.workflow.instance.node.WorkItemNodeInstance.cancel(WorkItemNodeInstance.java:382) 
      at org.jbpm.workflow.instance.impl.NodeInstanceImpl.cancel(NodeInstanceImpl.java:160) 
      at org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl.setState(WorkflowProcessInstanceImpl.java:406) 
      at org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl.setState(WorkflowProcessInstanceImpl.java:445) 
      at org.jbpm.process.instance.ProcessRuntimeImpl.abortProcessInstance(ProcessRuntimeImpl.java:551) 
      at org.drools.core.impl.StatefulKnowledgeSessionImpl.abortProcessInstance(StatefulKnowledgeSessionImpl.java:567) 
      at org.drools.core.command.runtime.process.AbortProcessInstanceCommand.execute(AbortProcessInstanceCommand.java:55) 
      at org.drools.core.command.runtime.process.AbortProcessInstanceCommand.execute(AbortProcessInstanceCommand.java:30) 
      at org.drools.core.fluent.impl.PseudoClockRunner.executeBatch(PseudoClockRunner.java:102) 
      at org.drools.core.fluent.impl.PseudoClockRunner.executeBatches(PseudoClockRunner.java:69) 
      at org.drools.core.fluent.impl.PseudoClockRunner.execute(PseudoClockRunner.java:61) 
      at org.drools.core.fluent.impl.PseudoClockRunner.execute(PseudoClockRunner.java:39) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:605) 
      at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:565) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.internalExecute(OptimisticLockRetryInterceptor.java:102) 
      at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:83) 
      at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:44) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:73) 
      at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:45) 
      at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39) 
      at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.internalExecute(ExecutionErrorHandlerInterceptor.java:66) at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:52) 
      at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:29) 
      at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:400) 
      at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:68) 
      at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:37) 
      at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:41) 
      at org.drools.core.command.impl.CommandBasedStatefulKnowledgeSession.abortProcessInstance(CommandBasedStatefulKnowledgeSession.java:153) 
      at org.jbpm.kie.services.impl.ProcessServiceImpl.abortProcessInstance(ProcessServiceImpl.java:220) ... 58 common frames omitted
      

      When aborting a case, it loops through all its subcases and:

      1. Aborts subcases workitems (this removes the workitems from the Entity Manager), including those from the parent. Though the parents one have a handler linked to them before removing it from the emf, so it waits before removing the entity from the emf https://github.com/kiegroup/drools/blob/master/drools-persistence/drools-persistence-jpa/src/main/java/org/drools/persistence/jpa/processinstance/JPAWorkItemManager.java#L121.
      2. Subcases workitems get removed from the emf https://github.com/kiegroup/drools/blob/master/drools-persistence/drools-persistence-jpa/src/main/java/org/drools/persistence/jpa/processinstance/JPAWorkItemManager.java#L131
      3. Notifies parent case which wa on hold and completes its corresponding work item (meaning this work item gets removed from the entity manager as well): https://github.com/kiegroup/drools/blob/master/drools-persistence/drools-persistence-jpa/src/main/java/org/drools/persistence/jpa/processinstance/JPAWorkItemManager.java#L169
      4. Now the work item mentioned in step 1, continues from where it was left and tries to remove the work item from the emf - but now it is no longer there, therefore the exception arises. https://github.com/kiegroup/drools/blob/master/drools-persistence/drools-persistence-jpa/src/main/java/org/drools/persistence/jpa/processinstance/JPAWorkItemManager.java#L131

      IMHO as a possible solution we could either:

      1. Before calling "context.remove" from the internalAbortWorkItem method, we should check again whether the entity is there or has been already removed by the handler in JPAWorkItemManager class: https://github.com/kiegroup/drools/blob/master/drools-persistence/drools-persistence-jpa/src/main/java/org/drools/persistence/jpa/processinstance/JPAWorkItemManager.java#L131
      2. Before removing any entity in the "remove" method from the JpaPersistenceContext class, check whether the entity has been removed from the emf. Though it might not be ideal for all cases: https://github.com/kiegroup/drools/blob/master/drools-persistence/drools-persistence-jpa/src/main/java/org/drools/persistence/jpa/JpaPersistenceContext.java#L142
      3. In jBPM, do not call abortWorkItem when this entity has been already completed.

       

        Gliffy Diagrams

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  antferna Antonio Fernandez Alhambra
                  Reporter:
                  antferna Antonio Fernandez Alhambra
                  Tester:
                  Gonzalo Muñoz Fernández
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  2 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: