@Override
    public void run() {
        ClassLoader old = WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(getClass());
        try {
            final TimerImpl timer = timerService.getTimer(timerId);
            try {
                if (cancelled) {
                    EJB3_TIMER_LOGGER.debugf("Timer task was cancelled for %s", timer);
                    return;
                }

                Date now = new Date();
                EJB3_TIMER_LOGGER.debugf("Timer task invoked at: %s for timer %s", now, timer);

                //we lock the timer for this check, because if a cancel is in progress or a running timeout is about to finish
                //and try to update the timer state after finish the inTimeout method,
                //we do not want to do the isActive check, but wait for the other transaction to finish
                //one way or another
                timer.lock();

                try {
                    // If a retry thread is in progress, we don't want to allow another
                    // interval to execute until the retry is complete. See JIRA-1926.
                    if (timer.isInRetry()) {
                        EJB3_TIMER_LOGGER.skipInvokeTimeoutDuringRetry(timer, now);
                        // compute the next timeout, See JIRA AS7-2995.
                        timer.setNextTimeout(calculateNextTimeout(timer));
                        timerService.persistTimer(timer, false);
                        scheduleTimeoutIfRequired(timer);
                        return;
                    }

                    // Check whether the timer is running local
                    // If the recurring timer running longer than the interval is, we don't want to allow another
                    // execution until it is complete. See JIRA AS7-3119
                    if (timer.getState() == TimerState.IN_TIMEOUT || timer.getState() == TimerState.RETRY_TIMEOUT) {
                        EJB3_TIMER_LOGGER.skipOverlappingInvokeTimeout(timer, now);

                        if (EJB3_TIMER_LOGGER.isDebugEnabled()) {
                            // WFLY-10542 log thread stack trace which is processing timer task in debug level to diagnose timer overlap
                            Thread otherThread = timer.getExecutingThread();
                            // can be null for clustered timers if the timer is executing on another node.
                            if (otherThread != null) {
                                final StringBuilder debugMsg = new StringBuilder()
                                        .append("Thread: ")
                                        .append(otherThread.getName())
                                        .append(" Id: ")
                                        .append(otherThread.getId())
                                        .append(" of group ")
                                        .append(otherThread.getThreadGroup())
                                        .append(" is in state: ")
                                        .append(otherThread.getState());
                                for (StackTraceElement ste : otherThread.getStackTrace()) {
                                    debugMsg.append(System.lineSeparator()).append(ste.toString());
                                }
                                EJB3_TIMER_LOGGER.debugf(debugMsg.toString());
                            }
                        }

                        Date newD = this.calculateNextTimeout(timer);
                        timer.setNextTimeout(newD);
                        timerService.persistTimer(timer, false);
                        scheduleTimeoutIfRequired(timer);
                        return;
                    }

                    // Check whether we want to run the timer
                    if (!timerService.shouldRun(timer)) {
                        EJB3_TIMER_LOGGER.debugf("Skipping execution of timer for %s as it is being run on another node or the execution is suppressed by configuration", timer.getTimedObjectId());
                        timer.setNextTimeout(calculateNextTimeout(timer));
                        scheduleTimeoutIfRequired(timer);
                        return;
                    }

                    if (!timer.isActive()) {
                        EJB3_TIMER_LOGGER.debug("Timer is not active, skipping this scheduled execution at: " + now + "for " + timer);
                        return;
                    }
                    // set the current date as the "previous run" of the timer.
                    timer.setPreviousRun(new Date());
                    Date nextTimeout = this.calculateNextTimeout(timer);
                    timer.setNextTimeout(nextTimeout);
                    // change the state to mark it as in timeout method
                    timer.setTimerState(TimerState.IN_TIMEOUT, Thread.currentThread());

                    // persist changes
                    timerService.persistTimer(timer, false);

                } finally {
                    timer.unlock();
                }
                try {
                    // invoke timeout
                    this.callTimeout(timer);
                } catch (Exception e) {
                    EJB3_TIMER_LOGGER.errorInvokeTimeout(timer, e);
                    try {
                        EJB3_TIMER_LOGGER.timerRetried(timer);
                        retryTimeout(timer);
                    } catch (Exception retryException) {
                        // that's it, we can't do anything more. Let's just log the exception
                        // and return
                        EJB3_TIMER_LOGGER.errorDuringRetryTimeout(timer, retryException);
                    }
                } finally {
                    this.postTimeoutProcessing(timer);
                }
            } catch (Exception e) {
                EJB3_TIMER_LOGGER.exceptionRunningTimerTask(timer, timedObjectId, e);
            }
        } finally {
            WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(old);
        }
    }
@ Override public void run ( ) { ClassLoader old = WildFlySecurityManager . setCurrentContextClassLoaderPrivileged ( getClass ( ) ) ; try { final TimerImpl timer = timerService . getTimer ( timerId ) ; try { if ( cancelled ) { EJB3_TIMER_LOGGER . debugf ( "Timer task was cancelled for %s" , timer ) ; return ; } Date now = new Date ( ) ; EJB3_TIMER_LOGGER . debugf ( "Timer task invoked at: %s for timer %s" , now , timer ) ; timer . lock ( ) ; try { if ( timer . isInRetry ( ) ) { EJB3_TIMER_LOGGER . skipInvokeTimeoutDuringRetry ( timer , now ) ; timer . setNextTimeout ( calculateNextTimeout ( timer ) ) ; timerService . persistTimer ( timer , false ) ; scheduleTimeoutIfRequired ( timer ) ; return ; } if ( timer . getState ( ) == TimerState . IN_TIMEOUT || timer . getState ( ) == TimerState . RETRY_TIMEOUT ) { EJB3_TIMER_LOGGER . skipOverlappingInvokeTimeout ( timer , now ) ; if ( EJB3_TIMER_LOGGER . isDebugEnabled ( ) ) { Thread otherThread = timer . getExecutingThread ( ) ; if ( otherThread != null ) { final StringBuilder debugMsg = new StringBuilder ( ) . append ( "Thread: " ) . append ( otherThread . getName ( ) ) . append ( " Id: " ) . append ( otherThread . getId ( ) ) . append ( " of group " ) . append ( otherThread . getThreadGroup ( ) ) . append ( " is in state: " ) . append ( otherThread . getState ( ) ) ; for ( StackTraceElement ste : otherThread . getStackTrace ( ) ) { debugMsg . append ( System . lineSeparator ( ) ) . append ( ste . toString ( ) ) ; } EJB3_TIMER_LOGGER . debugf ( debugMsg . toString ( ) ) ; } } Date newD = this . calculateNextTimeout ( timer ) ; timer . setNextTimeout ( newD ) ; timerService . persistTimer ( timer , false ) ; scheduleTimeoutIfRequired ( timer ) ; return ; } if ( ! timerService . shouldRun ( timer ) ) { EJB3_TIMER_LOGGER . debugf ( "Skipping execution of timer for %s as it is being run on another node or the execution is suppressed by configuration" , timer . getTimedObjectId ( ) ) ; timer . setNextTimeout ( calculateNextTimeout ( timer ) ) ; scheduleTimeoutIfRequired ( timer ) ; return ; } if ( ! timer . isActive ( ) ) { EJB3_TIMER_LOGGER . debug ( "Timer is not active, skipping this scheduled execution at: " + now + "for " + timer ) ; return ; } timer . setPreviousRun ( new Date ( ) ) ; Date nextTimeout = this . calculateNextTimeout ( timer ) ; timer . setNextTimeout ( nextTimeout ) ; timer . setTimerState ( TimerState . IN_TIMEOUT , Thread . currentThread ( ) ) ; timerService . persistTimer ( timer , false ) ; } finally { timer . unlock ( ) ; } try { this . callTimeout ( timer ) ; } catch ( Exception e ) { EJB3_TIMER_LOGGER . errorInvokeTimeout ( timer , e ) ; try { EJB3_TIMER_LOGGER . timerRetried ( timer ) ; retryTimeout ( timer ) ; } catch ( Exception retryException ) { EJB3_TIMER_LOGGER . errorDuringRetryTimeout ( timer , retryException ) ; } } finally { this . postTimeoutProcessing ( timer ) ; } } catch ( Exception e ) { EJB3_TIMER_LOGGER . exceptionRunningTimerTask ( timer , timedObjectId , e ) ; } } finally { WildFlySecurityManager . setCurrentContextClassLoaderPrivileged ( old ) ; } }
Invokes the timeout method through the {@link org.jboss.as.ejb3.timerservice.spi.TimedObjectInvoker} corresponding
to the {@link org.jboss.as.ejb3.timerservice.TimerImpl} to which this {@link TimerTask} belongs.
<p>
This method also sets other attributes on the {@link org.jboss.as.ejb3.timerservice.TimerImpl} including the
next timeout of the timer and the timer state.
</p>
<p>
Additionally, for calendar timers, this method even schedules the next timeout timer task
before calling the timeout method for the current timeout.
</p>