5 Replies Latest reply on Jun 26, 2013 6:24 AM by umb71

    timer job issues when disposing session in embedded j2ee process

    umb71

      Hi all,

      i'm using jBPM 5.4,  I have a knowledge session with a process instance in it, embebbed in  an ejb with container managed transaction, the process definition has a timer intermediate event in it:

       

      i'm using jpa persistence but the problem arises also with in memory session without persistence. I've utilized the CMTDisposeCommand class to register the synchronization with the transaction manager and implemented the afterCompletion method to be notified when the container finishes it's work committing the transaction; in the afterCompletion method i've utilized the DefaultProcessEventListener and implemented the afterProcessCompleted method  so i can (at least i thought it was so) dispose my knowledge session at the end of all the process elaboration.

      The problem is that the process is regularly terminated but it seams that the timer service sheduler is not aware of that fact neither that the session is disposed and it continuosly try to signal the timer event on the session. When i call the ksession.dispose, in the afterProcessCompleted method, i get the exception in the server console:

       

      SEVERE: Error when executing timer job

      java.lang.IllegalStateException: Illegal method call. This session was previously disposed.

              at org.drools.reteoo.DisposedReteooWorkingMemory.getLastIdleTimestamp(DisposedReteooWorkingMemory.java:562)

              at org.drools.impl.StatefulKnowledgeSessionImpl.getLastIdleTimestamp(StatefulKnowledgeSessionImpl.java:890)

              at org.drools.persistence.SingleSessionCommandService$EndOperationListenerImpl.endOperation(SingleSessionCommandService.java:334)

              at org.drools.common.AbstractWorkingMemory.endOperation(AbstractWorkingMemory.java:1365)

              at org.drools.common.AbstractWorkingMemory.executeQueuedActions(AbstractWorkingMemory.java:1006)

              at org.drools.impl.StatefulKnowledgeSessionImpl.executeQueuedActions(StatefulKnowledgeSessionImpl.java:866)

              at org.jbpm.process.instance.event.DefaultSignalManager.signalEvent(DefaultSignalManager.java:90)

              at org.jbpm.process.instance.timer.TimerManager$ProcessJob.execute(TimerManager.java:323)

              at org.drools.time.SelfRemovalJob.execute(SelfRemovalJob.java:15)

              at org.drools.time.impl.DefaultTimerJobInstance.call(DefaultTimerJobInstance.java:51)

              at org.drools.persistence.jpa.JpaTimerJobInstance.internalCall(JpaTimerJobInstance.java:43)

              at org.drools.persistence.jpa.JDKCallableJobCommand.execute(JDKCallableJobCommand.java:20)

              at org.drools.persistence.jpa.JDKCallableJobCommand.execute(JDKCallableJobCommand.java:6)

              at org.drools.command.impl.DefaultCommandService.execute(DefaultCommandService.java:36)

              at org.drools.persistence.SingleSessionCommandService.execute(SingleSessionCommandService.java:373)

              at org.drools.persistence.jpa.JpaTimerJobInstance.call(JpaTimerJobInstance.java:34)

              at org.drools.persistence.jpa.JpaTimerJobInstance.call(JpaTimerJobInstance.java:14)

              at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

              at java.util.concurrent.FutureTask.run(FutureTask.java:166)

              at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)

              at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)

              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

              at java.lang.Thread.run(Thread.java:722)

       

      giu 25, 2013 11:46:41 AM org.drools.time.impl.DefaultTimerJobInstance call

      WARNING: Unable to execute timer job!

      java.lang.IllegalStateException: Illegal method call. This session was previously disposed.

              at org.drools.reteoo.DisposedReteooWorkingMemory.getProcessInstance(DisposedReteooWorkingMemory.java:382)

              at org.drools.impl.StatefulKnowledgeSessionImpl.getProcessInstance(StatefulKnowledgeSessionImpl.java:297)

              at org.jbpm.process.instance.timer.TimerManager$ProcessJob.execute(TimerManager.java:335)

              at org.drools.time.SelfRemovalJob.execute(SelfRemovalJob.java:15)

              at org.drools.time.impl.DefaultTimerJobInstance.call(DefaultTimerJobInstance.java:51)

              at org.drools.persistence.jpa.JpaTimerJobInstance.internalCall(JpaTimerJobInstance.java:43)

              at org.drools.persistence.jpa.JDKCallableJobCommand.execute(JDKCallableJobCommand.java:20)

              at org.drools.persistence.jpa.JDKCallableJobCommand.execute(JDKCallableJobCommand.java:6)

              at org.drools.command.impl.DefaultCommandService.execute(DefaultCommandService.java:36)

              at org.drools.persistence.SingleSessionCommandService.execute(SingleSessionCommandService.java:373)

              at org.drools.persistence.jpa.JpaTimerJobInstance.call(JpaTimerJobInstance.java:34)

              at org.drools.persistence.jpa.JpaTimerJobInstance.call(JpaTimerJobInstance.java:14)

              at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

              at java.util.concurrent.FutureTask.run(FutureTask.java:166)

              at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)

              at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)

              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

              at java.lang.Thread.run(Thread.java:722)

       

      I've also tried to cancel any TimerJobInstance in the TimerService prior to dispose the session but the problem is still present. Am i doing something wrong? Missing something? What is the correct way of disposing session with (terminated) timer events in it?

       

      Thanks.

      Umberto

        • 1. Re: timer job issues when disposing session in embedded j2ee process
          jsvitak

          Hi Umberto,

          jBPM engine uses knowledge sessions for running process instances. Listeners are registered in the sessions. So your processes instance has not ended yet and you are trying to dispose its underlying session, which also contains your listener. That won't work.

           

          So to solve the problem, I think that you should not try to dispose the session inside listener method. You should implement another (waiting) mechanism, which will dispose the session only when it is safe - when all process instances of the session are not running.

           

          There are many patterns how to use sessions. For example:

          - waiting mechanism, for example you can use waiting after startProcess() method, decrement CountDownLatch in the listener and after that dispose the session

          - or you should not dispose the session when using timers (singleton session pattern) - because if you dispose session directly after startProcess(), the timer will not fire, because its session is not active

          - ...

           

          My two cents.

          • 2. Re: timer job issues when disposing session in embedded j2ee process
            umb71

            Hi Jiri,

            thanks for your response. Indeed i've followed the indication of Maciej Swiderski in this post http://mswiderski.blogspot.it/2012/10/dispose-session-in-cmt-environment.html when it is clearly explained that in case such mine, CMT j2ee object embedded processes, the correct pattern to use to dispose a session seems to be the one that utilized the ProcessEventListeners. And without timers in the process definition it works like a charm. When i'm in the afterProcessCompleted method I'm sure the process is terminated, i've

            checked with appropriate code: no process instance active, nor timer node instances.

             

            I repeat my guess: it seems that the timer service sheduler is not aware of the fact that the session is disposed and it continuosly try to signal the timer event on the session itself.

             

            Regards.

            Umberto

            • 3. Re: timer job issues when disposing session in embedded j2ee process
              jsvitak

              Hi Umberto,

               

              Thanks for the link to Maciej's blog. It is helpful. Maybe I am missing something, but Maciej uses there own defined CMTDisposeCommand, not ProcessEventListener. The same applies for method name - he uses afterCompletion() to dispose, not afterProcessCompleted(). Is it possible that this is the problem?

              Also keep in mind, that timers are special case and there are scenarios, where you cannot use session per process instance pattern - as I said timer cannot trigger in disposed session.

              • 4. Re: timer job issues when disposing session in embedded j2ee process
                umb71

                Hi Jiri,

                you're right, i ain't been so clear:  i've modified the Maciej's CMTDisposeCommand class, in the afterCompletion method i've introduced the registration on the ProcessEventListener interface and implemented the afterProcessCompleted method, as a mechanism to wait for process completion. As i said, the timer in the process and the process itself are terminated when i enter in the afterProcessCompleted method, so i don't think that's the problem. But you have given me a correct suggestion when you said that the events listeners are part of the session, so it's probably not correct dispose the session when i'm in the afterProcessCompleted. I will try to wait for process completion directly in the afterCompletion method, using another strategy, and let you know the results.

                 

                In the mean time i thank you very much your help.

                • 5. Re: timer job issues when disposing session in embedded j2ee process
                  umb71

                  Hi,

                  ok, i've found a solution. In my EJB project, in the method exposed, i create a knowledge session per call, and a single process instance:

                   

                  1. create the process instance:

                   

                              logger.debug(">>> create a process instance");             ProcessInstance procInstance = ksession.createProcessInstance("test.TestComplete", params);

                   

                  2. register transaction manager synchronization using Maciej's original CMTDisposeCommand  (in the afterCompletion method i dispose the ksession):

                   

                   

                              logger.debug(">>> register transaction synchronization");

                              ksession.execute(new CMTDisposeCommand());

                   

                  3. create and register a new class, CMTProcessEventListener, to listen for the process complete event (code attached below)

                   

                              CMTProcessEventListener procEventListener = new CMTProcessEventListener(procInstance.getId(),ejbName);

                              logger.debug(">>> add process events listener");

                              ksession.addEventListener(procEventListener);

                   

                  4. start the process instance execution:

                   

                              logger.debug(">>> start the process instance");

                              ksession.startProcess(procInstance.getProcessId());

                   

                  5. at this point, i've implemented a cycle in my code to wait until the procEventListener.isProcessCompleted() is true before terminate the ejb method.

                   

                  The jBPM engine notify the CMTProcessEventListener after the process complete, timer included, the EJB method ends so the ejb container commits the transaction and call the afterCompletion method so i can dispose che session.

                   

                  Thank you very much Jiri, hope this help someone else too.

                   

                  Umberto