Saturday, January 24, 2015

EJB Timer Service

Each stateless session bean timer is associated with only a specific session bean. When a timer for a stateless session bean goes off, the container picks up any one of the instances of that stateless bean from the instance pool and calls its timeout callback method.

When a stateless session bean implements the javax.ejb.TimedObject interface, or contains an @javax.ejb.Timeoutcallback method, its life-cycle changes to include the servicing of timed events. The Timer Service chooses an instance of the bean from the instance pool when a timer expires; if there are no instances in the pool, the container creates one. After the time out method finishes, the instance is returned to the pool.

You should not store state in a stateless bean for your timeout call back method. Alternative would be to store it in the db or to store it in a singleton bean.

Again, the instance of the stateless session bean picked up later from the pool when time out occurs could be different from the instance you set the timer. And the states could be of course different, actually very likely lost.

EJB timers can't be queried. The information is there in the container, but you need hacks and reflective tricks to get to it, which is of course not recommended. You have to build a workaround or use something else like Quartz.

Timers are persistent by default. If you restart the server, the timers restart. But it may takes longer to restart and during that period all the timers fire at once. If you redeploy the application all the timers are lost. Timers are tied to the application, not the server.

For recovery, you can store the TimerHandle and the scheduling information together in the database. When the application starts up it creates a TimerRepair singleton bean which calls repairTimers on any any classes that require it. The repairTimers method tries to recover each Timer which has a TimerHandle. If the Timer recovery throws an exception it will recreate the Timer from the scheduling information.

ScheduledExecutorService could be used instead of Timer in some cases:

Timer has only one execution thread, so long-running task can delay other tasks. ScheduledThreadPoolExecutor can be configured with any number of threads. Furthermore, you have full control over created threads.

Runtime exceptions thrown in Timer Task kill that one thread, thus kill that Timer. i.e. scheduled tasks will not run anymore. ScheduledThreadExecutor not only catches runtime exceptions, but it lets you handle them if you want (by overriding afterExecute method from ThreadPoolExecutor). Task which throws exception will be canceled, but other tasks will continue to run.

Example of EJB Timer Service:
/**
 *
 * @author it.i88.ca
 */
@Stateless
public class GeneralSchedule {

    /**
     *
     * @param timer
     */
    @Schedules({
        @Schedule(hour = "17", minute = "18", info = "by it.i88.ca", persistent = false),
        @Schedule(hour = "17", minute = "46", info = "by it.i88.ca", persistent = false)

    })
    public void printTime(final Timer timer) {
        System.out.println(getClass().getName() + ": " + new Date() + ":");

    }

    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    public void printTime2(final Timer timer) {
        System.out.println("it.i88.ca");
    }
}

Popular Posts