10 Replies Latest reply on Feb 17, 2010 10:38 AM by Sascha Effert

    Long running thread: Best practice?

    Sascha Effert Newbie

      Hello,


      I need to implement a long running process in the Background of my application, several my run at same time. I need the possibility to cancel this processes on some changes in my model. Therefore I would like to create a POJO which has a @Asynchronous tagged method to start the process. If the process ends I will raise an Event, so the rest of my applications can notify. To be able to cancel my process I would like to listen on an other event. My fist idea is something like the following:



      public class worker {
         private boolean stop;
         private Long id;
         @In Events events;

         @Asynchronous
         public void doWork(Long id) {
            this.id = id;
            stop = false;
            while (!stop) {
               //do some work
            }
            events.raiseAsynchronousEvent("workerFinished", id);
         }

         @Observer("endWorker")
         private void endWork(Long id) {
            if ((id != null) && (id.equals(this.id))
               stop = true;
         }
      }


      I am not quite sure, if raising the event "endWorker" will result in a call in all running Workers and I am not sure what happens if such an event is raised while no worker is running. At the moment I think on a new Event there will be created a worker, which "endWork" Method is called, and the rest of the workers will not be notified, is it right? I was also thinking about the events.addListener Method to subscribe for the Event for each Worker in his "doWork" method, but I have not found anything about how to do it. I would have to give it a method binding in EL, but my POJO is not accessible this way. Can I just use "this"?


      I would be happy for any suggestions...


      bests


      Sascha

        • 1. Re: Long running thread: Best practice?
          Nikolay Elenkov Master

          Use Quartz or EJB timers. Those have handles that can be used to cancel the process. Unless your jobs are application scoped, you can't observe events.

          • 2. Re: Long running thread: Best practice?
            Sascha Effert Newbie

            If necessary, I can also application scope my worker, but I am not sure, what happens with the @Asynchronous call then. I think there will not be different Objects for each Asynchronous call, right?


            I also had a look at the QuartzTriggerHandle to realize my worker, but I do not think, that it helps. There is a method to cancel the Job, but my problem is, that I have to tell my worker to cancel itself, because it my not be canceled during one run of the while-loop.


            Because I accidently misformed the code above, I add it here again. Sorry for this...


            public class worker { 
               private boolean stop;
               private Long id;
               @In Events events;
            
               @Asynchronous public void doWork(Long id) {
                  this.id = id;
                  stop = false;
                  while (!stop) { 
                     //do some work 
                  }
                  events.raiseAsynchronousEvent("workerFinished", id);
               } 
            
               @Observer("endWorker") 
               private void endWork(Long id) { 
                  if ((id != null) && (id.equals(this.id)) 
                     stop = true; 
               } 
            } 
            



            • 3. Re: Long running thread: Best practice?
              Nikolay Elenkov Master

              Sascha Effert wrote on Nov 16, 2009 13:19:


              If necessary, I can also application scope my worker, but I am not sure, what happens with the @Asynchronous call then. I think there will not be different Objects for each Asynchronous call, right?



              Right, only one instance can be in application scope. Generally, jobs/background components should be stateless and you'd better avoid application scope.



              I also had a look at the QuartzTriggerHandle to realize my worker, but I do not think, that it helps. There is a method to cancel the Job, but my problem is, that I have to tell my worker to cancel itself, because it my not be canceled during one run of the while-loop.


              If using Quartz, you should save the handle in the calling component, and cancel from there. There is no need for the component to cancel itself, and no need for the while loop. Something like this:


              // worker starts on a different thread
              QuartzTriggerHandle handle = worker.doWork(id);
              
              // in your Action class, etc.                                   
              handle.cancel();
              



              If have to make sure work is not cancelled during the loop run, you will have to implement your own notification mechanism (via the DB, etc.).


              HTH

              • 4. Re: Long running thread: Best practice?
                Sascha Effert Newbie

                That is not nice. So there is really no way to subscribe an Object for an event? I can not really believe this... What will happen in my Worker, if the cancel-method is called? Is there a way for my worker to catch this call and to do some stuff before? Then I would just add there something to let it wait until the worker can be cancelled...

                • 5. Re: Long running thread: Best practice?
                  Nikolay Elenkov Master

                  Sascha Effert wrote on Nov 16, 2009 14:46:


                  That is not nice. So there is really no way to subscribe an Object for an event? I can not really believe this...


                  The Seam event mechanism is rather simple: it just looks for a component with the specified observer, and call the annotated method.
                  If a component doesn't exist, it will be created (if create=true). So to 'subscribe', you need to make sure you component's scope is the seam or wider as the calling component's. Since jobs run in a different thread, they do not have access to session and conversation. That leaves you with event (not really usable) and application (only good for singleton-like components).



                  What will happen in my Worker, if the cancel-method is called? Is there a way for my worker to catch this call and to do some stuff before? Then I would just add there something to let it wait until the worker can be cancelled...


                  You have a number of options, however none of them is integrated with Seam, you will have to do some work.



                  1. notify your jobs via the DB

                  2. use JMS to send interrupt instructions to your jobs

                  3. if using Quartz, look at InterruptableJob

                  4. use your own job pooling and notification (you don't really need to use @Asynchronous)


                  • 6. Re: Long running thread: Best practice?
                    iwan Nugraha Newbie

                    Hi Nikolay,


                    i'm newbie using seam, and i have a problem with long running processing, my session always closed before process acomplished.


                    i was read abouth Asynchronous, but i'm still confuse. can you show a complete example a better way for long running processing.


                    Thank you,


                    Iwan Nugraha.

                    • 7. Re: Long running thread: Best practice?
                      Sascha Effert Newbie

                      In my applications the long running processes are no more bound to any session. I have never tried to implement long rinnung threads which are bound to a Session. What should happen with your Thread if the session ends?


                      bests


                      Sascha

                      • 8. Re: Long running thread: Best practice?
                        scott duke Novice

                        I too am looking for a way to process a lot of records.


                        I know that jboss has a Thread Pool, which, if I am not mistaken. will live for a predefined amount of time without any tasks. Look in jboss-services.xml.


                        If I understand correctly, with each pool thread you call, you can have a separate entityManager. (If I am mistaken, someone please tell me.) I am looking to see if this has to be a certain scopeType. There is an article I found in my search Accelerating Applications with Java 5 Concurrency. It is a couple of years old, but it is a good article.


                        I might try to use something similar. But, if something already exists out there, then it would keep me from having to support extra code.


                        Scott

                        • 9. Re: Long running thread: Best practice?
                          Nikolay Elenkov Master

                          scott duke wrote on Feb 16, 2010 20:40:


                          I might try to use something similar. But, if something already exists out there, then it would keep me from having to support extra code.



                          The reference is always a good place to start.

                          • 10. Re: Long running thread: Best practice?
                            Sascha Effert Newbie

                            Hello Scott,


                            I do not think that it is supported in JBoss to use Executors or any J2SE Threading mechanisms. At least if you are running in a clustered environment this could end up in problems, because the AS does not know about this Threads. If I am wrong, this would make my life much easier...


                            bests


                            Sascha