6 Replies Latest reply on Jan 8, 2006 12:39 PM by Dimitris Andreadis

    [JBAS-1926] - Behavior of EJB Timer Service during exception

    Nathan Pahucki Newbie

      I am looking at http://jira.jboss.com/jira/browse/JBAS-1926?page=all. I have been able to duplicate the issue described by using the following code in a session bean:

      public void ejbTimeout(Timer timer)
       {
       System.out.println("*****GOT TIMING EVENT. TIMER=" + timer.toString());
       if (!failedAlready) {
       failedAlready = true;
       m_sc.setRollbackOnly();
       System.out.println("** INDICATING FAILURE...");
       } else {
       try {
       System.out.print("** DOING TASK.");
       for(int i = 1; i<=10; i++) {
       Thread.sleep(1000);
       System.out.print(" " + i);
       }
       System.out.println();
       } catch (InterruptedException e) {
       e.printStackTrace(); //TODO: handle this!
       }
       System.out.println("** DONE with timer 'processing'");
       }
       }


      The timer is created with:
      Timer timer = ts.createTimer(1000,1000,"MyTestTimer");



      When this (admittedly contrived) example is run you will see interleaved values for the variable 'i' in the for loop on the console as two threads are executing the ejbTimeout() method at the same time. One is the retry thread, the other is the regular interval timer thread which timedout while the the retry was running. Once the retry thread completes, you see the 'normal' interval timer output repeat immediately after the ejbTimeout() method completes (because the timeout is shorter than the time it takes the task to execute)

      The EJB spec does not seem to specifically address this situation, only saying that if the ejbTimeout() transaction fails or is rolledback, that the timeout must be tried again.

      From 22.4.2 in EJB 2.1 Spec:
      If the Bean Provider invokes the setRollbackOnly method from within the ejbTimeout method, the container must rollback the transaction in which the ejbTimeout method is invoked. This has the effect of rescinding the timer expiration. The container must retry the timeout after the transaction rollback.


      The spec does mention that the bean must be prepared for spurious callings of ejbTimeout() after calling cancel on the timer because of potential race conditions. On the other hand, we do prevent the timer from firing again if the time it takes to execute the ejbTimeout() method exceeds the timer's interval.

      So, since this is somewhat of a gray area, what are people's feelings on the correct behavior here. Should we prevent the inerval timer from firing while a retry is in progress, or is this something where the bean provider should provide the logic to detect the same task running concurrently in the retry thread?

      Thanks in advance for the feedback.




        • 1. Re: [JBAS-1926] - Behavior of EJB Timer Service during excep
          Dimitris Andreadis Master

          My take is we should probably stop the regular timer callbacks if we are in re-try mode. Fixing this though doesn't seem easy with the existing design.

          • 2. Re: [JBAS-1926] - Behavior of EJB Timer Service during excep
            Nathan Pahucki Newbie

            A simple solution might be to do the following, add this method to org.jboss.ejb.txtimer.TimerImpl:

             public boolean isInRetry() {
             return timerState == RETRY_TIMEOUT;
             }
            


            and then modify the TimerTaskImpl innerclass' run() method to change it from :

             if (isActive() && periode > 0)
             nextExpire += periode;
            
             if (isActive())
             {
             .........
             }
            


            to:
             if (isActive() && !isInRetry() && periode > 0)
             nextExpire += periode;
            
             if (isActive() && !isInRetry())
             {
             .........
             }
            



            Can anyone find a reason that this proposal would break something? As tested, it does solve the immediate issue.

            • 3. Re: [JBAS-1926] - Behavior of EJB Timer Service during excep
              Scott Stark Master

              If we delay backlogged timeout calls for a given timer, we should delay the execution of the retry as well. This change is not really redispatching the rolled back timer though. Isn't just preventing the immeadiate redispatch?

              What happens if you schedule two single duration timers? I would expect that the rollback of the second timer with this change is not being resent.

              • 4. Re: [JBAS-1926] - Behavior of EJB Timer Service during excep
                Nathan Pahucki Newbie

                Please forgive me if I didn't fully grok what you meant in your reply. Here is my clarification:

                If we delay backlogged timeout calls for a given timer, we should delay the execution of the retry as well.


                Technically, this change does not delay backlogged calls, it simply ignores an interval firing if the retry is in progress. The next interval will fire at the next interval time, provided that the retry is completed. I am not sure I understand why we should delay the execution of the retry. It is already delayed by a fixed time from the point of failure by the FixedDelayRetryPolicy. Are you concerned about making sure that the retry does not run, if during the retry delay, the interval timer fired again beating the retry to the punch? I don't think this can happen with the proposed changes, because as soon as the transaction fails, the state of the timer will be set to RETRY_TIMEOUT, and no regular intervals will run until the state is transitioned out of RETRY_TIMEOUT.

                This change is not really redispatching the rolled back timer though. Isn't just preventing the immeadiate redispatch?


                You are correct, this change does not redispatch the rolled back timer at all, that is handled already by FixedDelayRetryPolicy.RetryThread. The changes only prevent an interval triggered dispatch (calling of the ejbTimeout() method) from happening while a retry is in progress (which includes the delay for the retry).

                What happens if you schedule two single duration timers?


                The issue described in the JIRA issue does not happen with a single duration timer because the problem is the interval firing *again* while the retry is in progress. For a single duration timer, there will only be a single firing, so no danger of a second firing during the retry exists. The proposed changes should not affect single duration timers at all since the run() method of the TimerImpl.TimerTaskImpl will only ever be called once, and when called, the state will not be RETRY_TIMEOUT.

                I would expect that the rollback of the second timer with this change is not being resent.


                Perhaps you would not mind expounding upon your expectation. I am not sure how one timer would affect the the other with the proposed changes. Each timer is a separate TimerImpl instance, and therefore each has state independent of the other, and each TimerImpl instance seems to call back on a separate instance of the session bean. I did run a test with two single timers and two interval timers, and in both cases, both timers were retried as expected.

                Is there some transaction nuance you have mind?

                Thank you for your feedback.

                • 5. Re: [JBAS-1926] - Behavior of EJB Timer Service during excep
                  Scott Stark Master

                  Ok, I see. The change is fine then as there was just some confusion on how the rolled back timer was being dispatched.

                  • 6. Re: [JBAS-1926] - Behavior of EJB Timer Service during excep
                    Dimitris Andreadis Master

                    Made some changes to the committed code, see the JIRA case.