4 Replies Latest reply on Apr 1, 2014 12:27 PM by aartigao

    GlobalTimerService and DisposableCommandService running in CMT

    aartigao

      Hi community,

       

      We have some questions regarding the use of GlobalTimerService running inside Container Managed Transactions (using ContainerManagedTransactionManager as environment transaction manager). We post this just to know if we're doing something bad or if it's a "bug", before opening a JIRA issue. Here we go:

       

      We are running JBPM through EJB service layer (it's mandatory for us to adhere to global transactions, so we can't use Bean Managed Transactions). After https://issues.jboss.org/browse/JBPM-4270 if we run BPM process without timers, all goes smooth... but if we use timers two problems arise:

       

      1. Wheter we use ThreadPoolSchedulerService or QuartzSchedulerService, since they span custom threads that doesn't have J2EE context, no transaction is present in the thread, causing ContainerManagedTransactionManager to fail at transaction synchronization. We solved this problem implementing an in-house solution of GlobalSchedulerService that uses EJB timers to execute jobs inside CMT (probably Quartz would work with the lastest release and some configuration/implementation but our solution solves runtime execution in clustering without the need of creating Quartz tables for every different domain, and defining quartz.properties for every domain-node). We think that this doesn't break the code, because GlobalSchedulerService is pluggable, and everyone can implement their own custom solution. Are we right?
      2. GlobalTimerService uses DisposableCommandService. Inside GlobalJpaTimerJobInstance we have the following snippet:

       

       public Void call() throws Exception {
              CommandService commandService = null;
              try { 
                  JDKCallableJobCommand command = new JDKCallableJobCommand( this );
                  if (scheduler == null) {
                      scheduler = (InternalSchedulerService) TimerServiceRegistry.getInstance().get(timerServiceId);
                  }
                  commandService = ((GlobalTimerService) scheduler).getCommandService(getJobContext());   
                  commandService.execute( command );
                  GlobalJPATimerJobFactoryManager timerService = ((GlobalJPATimerJobFactoryManager)((GlobalTimerService) scheduler).getTimerJobFactoryManager());
                  timerService.removeTimerJobInstance(((DefaultJobHandle)getJobHandle()).getTimerJobInstance());
                  
                  return null;
              } catch( Exception e ) { 
               e.printStackTrace();
                  throw e;
              } finally {
                  if (commandService != null && commandService instanceof DisposableCommandService) {
                      ((DisposableCommandService) commandService).dispose();
                  }
              }
          }
      

       

      In finally clause it forces the disposition of CommandService, who disposes the RuntimeEngine. This disposition causes errors, because after transaction completion (remember CMT) it tries to dispose again a session that was previously disposed.

       

      We are not sure if this is the expected behaviour... do we really need a DisposableCommandService? Or perhaps DisposableCommandService would check first the transaction manager and dispose only if it's not a ContainerManagedTransactionManager?

       

      Only for checking purposes, we commented the finally clause, and worked well (the session was disposed after transaction) but before opening a JIRA or submitting a patch we would like to comment this situation with core developers.

       

      Many thanks for your attention.

        • 1. Re: GlobalTimerService and DisposableCommandService running in CMT
          swiderski.maciej

          Alan Artigao wrote:

           

          Hi community,

           

          We have some questions regarding the use of GlobalTimerService running inside Container Managed Transactions (using ContainerManagedTransactionManager as environment transaction manager). We post this just to know if we're doing something bad or if it's a "bug", before opening a JIRA issue. Here we go:

           

          We are running JBPM through EJB service layer (it's mandatory for us to adhere to global transactions, so we can't use Bean Managed Transactions). After https://issues.jboss.org/browse/JBPM-4270 if we run BPM process without timers, all goes smooth... but if we use timers two problems arise:

           

          1. Wheter we use ThreadPoolSchedulerService or QuartzSchedulerService, since they span custom threads that doesn't have J2EE context, no transaction is present in the thread, causing ContainerManagedTransactionManager to fail at transaction synchronization. We solved this problem implementing an in-house solution of GlobalSchedulerService that uses EJB timers to execute jobs inside CMT (probably Quartz would work with the lastest release and some configuration/implementation but our solution solves runtime execution in clustering without the need of creating Quartz tables for every different domain, and defining quartz.properties for every domain-node). We think that this doesn't break the code, because GlobalSchedulerService is pluggable, and everyone can implement their own custom solution. Are we right?

          that is completely valid case. You could use quartz with work manager (jee spec) but since you all rely on EJB then the ejb timer based scheduler service is the way to go - feel free to contribute that back if you like

           

          Alan Artigao wrote:

           

          1. GlobalTimerService uses DisposableCommandService. Inside GlobalJpaTimerJobInstance we have the following snippet:

           

          1. public Void call() throws Exception { 
          2.         CommandService commandService = null
          3.         try {  
          4.             JDKCallableJobCommand command = new JDKCallableJobCommand( this ); 
          5.             if (scheduler == null) { 
          6.                 scheduler = (InternalSchedulerService) TimerServiceRegistry.getInstance().get(timerServiceId); 
          7.             } 
          8.             commandService = ((GlobalTimerService) scheduler).getCommandService(getJobContext());    
          9.             commandService.execute( command ); 
          10.             GlobalJPATimerJobFactoryManager timerService = ((GlobalJPATimerJobFactoryManager)((GlobalTimerService) scheduler).getTimerJobFactoryManager()); 
          11.             timerService.removeTimerJobInstance(((DefaultJobHandle)getJobHandle()).getTimerJobInstance()); 
          12.              
          13.             return null
          14.         } catch( Exception e ) {  
          15.          e.printStackTrace(); 
          16.             throw e; 
          17.         } finally
          18.             if (commandService != null && commandService instanceof DisposableCommandService) { 
          19.                 ((DisposableCommandService) commandService).dispose(); 
          20.             } 
          21.         } 
          22.     } 

           

          In finally clause it forces the disposition of CommandService, who disposes the RuntimeEngine. This disposition causes errors, because after transaction completion (remember CMT) it tries to dispose again a session that was previously disposed.

           

          We are not sure if this is the expected behaviour... do we really need a DisposableCommandService? Or perhaps DisposableCommandService would check first the transaction manager and dispose only if it's not a ContainerManagedTransactionManager?

           

          Only for checking purposes, we commented the finally clause, and worked well (the session was disposed after transaction) but before opening a JIRA or submitting a patch we would like to comment this situation with core developers.

          we can consider this as a bug as the assumption made by the GlobalJpaTimerJobInstance is that the transaction is managed on command service level. Since you have ejb that actually invokes the timer the assumption is not valid any more. What we could do is to extend the GlobalSchedulerService to provide a hint if the transaction is managed by it or not. I assume you implemented GlobalSchedulerService, right? Then if the scheduler service claims to control transaction the DisposableService would not do any dispose. Wdyt?

           

          HTH

          • 2. Re: GlobalTimerService and DisposableCommandService running in CMT
            aartigao

            Maciej Swiderski escribió:

             

              that is completely valid case. You could use quartz with work manager (jee spec) but since you all rely on EJB then the ejb timer based scheduler service is the way to go - feel free to contribute that back if you like

               

              OK, since the EJB Scheduler is at this moment under development, I will contribute the code in a few weeks, when we have tested conciously.

               

              we can consider this as a bug as the assumption made by the GlobalJpaTimerJobInstance is that the transaction is managed on command service level. Since you have ejb that actually invokes the timer the assumption is not valid any more. What we could do is to extend the GlobalSchedulerService to provide a hint if the transaction is managed by it or not. I assume you implemented GlobalSchedulerService, right? Then if the scheduler service claims to control transaction the DisposableService would not do any dispose. Wdyt?

               

              HTH

               

              Seems a reasonable solution Do I need to open a JIRA for this?

               

              Thank you!

              • 3. Re: GlobalTimerService and DisposableCommandService running in CMT
                swiderski.maciej

                Alan Artigao wrote:

                 

                Maciej Swiderski escribió:

                 

                  that is completely valid case. You could use quartz with work manager (jee spec) but since you all rely on EJB then the ejb timer based scheduler service is the way to go - feel free to contribute that back if you like

                   

                  OK, since the EJB Scheduler is at this moment under development, I will contribute the code in a few weeks, when we have tested conciously.

                  sure, take your time, more than happy to wait for valuable contribution

                   

                  Alan Artigao wrote:

                   

                  we can consider this as a bug as the assumption made by the GlobalJpaTimerJobInstance is that the transaction is managed on command service level. Since you have ejb that actually invokes the timer the assumption is not valid any more. What we could do is to extend the GlobalSchedulerService to provide a hint if the transaction is managed by it or not. I assume you implemented GlobalSchedulerService, right? Then if the scheduler service claims to control transaction the DisposableService would not do any dispose. Wdyt?

                   

                  HTH

                   

                  Seems a reasonable solution Do I need to open a JIRA for this?

                  yes, please file a jira

                  • 4. Re: GlobalTimerService and DisposableCommandService running in CMT
                    aartigao

                    JIRA Issue opened: https://issues.jboss.org/browse/JBPM-4287

                     

                    Thank you very much.