Uploaded image for project: 'JBoss Enterprise Application Platform'
  1. JBoss Enterprise Application Platform
  2. JBEAP-147

EJB timer blocked after trigger+suspend+activate operations and JDBC storage

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 7.0.0.DR7
    • 7.0.0.DR2
    • EJB
    • None
    • Hide

      The easiest is probably to build WildFly 10.0.0.Alpha1, reconfigure the distro to use the H2 ExampleDS as JDBC storage for EJB timers and then run PersistentCalendarTimerManagementTestCase#testSuspendAndTrigger from basic testsuite

      Show
      The easiest is probably to build WildFly 10.0.0.Alpha1, reconfigure the distro to use the H2 ExampleDS as JDBC storage for EJB timers and then run PersistentCalendarTimerManagementTestCase#testSuspendAndTrigger from basic testsuite

      Scenario:

      The AS is configured to use a JDBC storage for EJB timers (using the H2 ExampleDS is sufficient for reproduction)
      There is a persistent calendar timer going off every few seconds
      The 'trigger' management operation is called on that timer
      The timer goes off one time extra, as expected
      The 'suspend' management operation is called on that timer
      After a few seconds, the 'activate' operation is called on that timer
      The timer will never go off again (not even by invoking 'trigger' operation)

      The cause:

      Each time the timer goes off, a new java.util.TimerTask is scheduled to handle the next alarm
      When the 'trigger' operation is invoked, the TimerServiceImpl computes the timestamp of the next alarm and schedules a new TimerTask
      The problem is that this new TimerTask overwrites the one currently registered in the TimerServiceImpl, because the TimerServiceImpl assigns TimerTasks to Timers using a map: https://github.com/wildfly/wildfly/blob/10.0.0.Alpha1/ejb3/src/main/java/org/jboss/as/ejb3/timerservice/TimerServiceImpl.java#L905 - the TimerServiceImpl loses the reference to the previously registered TimerTask and doesn't cancel it
      From now on, each new alarm registers the next TimerTask, but makes TimerServiceImpl forget the previous one
      After some time, when the 'suspend' operation is called, the TimerServiceImpl cancels its stored TimerTask. However, it doesn't know that there is another scheduled elsewhere
      The TimerTask goes off during the time when the timer is suspended.
      DatabaseTimerPersistence checks whether the TimerTask can run and sets the Timer's state to IN_TIMEOUT if yes (https://github.com/wildfly/wildfly/blob/10.0.0.Alpha1/ejb3/src/main/java/org/jboss/as/ejb3/timerservice/persistence/database/DatabaseTimerPersistence.java#L395). However, this is done BEFORE checking whether the timer is suspended. DatabaseTimerPersistence commits this change. Then comes the mentioned check (https://github.com/wildfly/wildfly/blob/10.0.0.Alpha1/ejb3/src/main/java/org/jboss/as/ejb3/timerservice/task/TimerTask.java#L141) and it fails, so the Timer will not go off, but the Timer state remains IN_TIMEOUT forever!
      With every next invocation, as the timer's state remains IN_TIMEOUT, all invocations are skipped.

              jmartisk@redhat.com Jan Martiska
              jmartisk@redhat.com Jan Martiska
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated:
                Resolved: