Partner – Payara – NPI (cat=Jakarta EE)
announcement - icon

Can Jakarta EE be used to develop microservices? The answer is a resounding ‘yes’!

>> Demystifying Microservices for Jakarta EE & Java EE Developers

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In a previous article, we demonstrated how to schedule tasks in Spring using @Scheduled annotation. In this article, we will demonstrate how to achieve the same by using the timer service in a Jakarta EE application for each case presented in the previous article.

2. Enable Support for Scheduling

In a Jakarta EE application, there is no need to enable support for timed tasks. The timer service is a container managed service that allows applications to call methods that are scheduled for time-based events. As an example, an application may have to run some daily reports at a certain hour in order to generate statistics.

There are two types of timers:

  • Programmatic timers: the timer service can be injected into any bean (except a stateful session bean) and the business logic should be placed in a method annotated with @Timeout. The timer can be initialized by a method annotated @PostConstruct of the beans or it can also be initialized just by calling a method.
  • Automatic timers: the business logic is placed in any method annotated with @Schedule or @Schedules. These timers are initialized as soon as the application starts.

So let’s get started with our first example.

3. Schedule Task with a Fixed Delay

In Spring this is done simply by using the @Scheduled(fixedDelay = 1000) annotation. In this case, the duration between the end of the last execution and the start of next execution is fixed. The task always waits until the previous one is finished.

Doing exactly same thing in Jakarta EE is a little bit harder to achieve because there is no similar built-in mechanism provided, nevertheless, a similar scenario can be implemented with a bit of extra coding. Let’s have a look at how this is done:

@Singleton
public class FixedTimerBean {

    @EJB
    private WorkerBean workerBean;

    @Lock(LockType.READ)
    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    public void atSchedule() throws InterruptedException {
        workerBean.doTimerWork();
    }
}
@Singleton
public class WorkerBean {

    private AtomicBoolean busy = new AtomicBoolean(false);

    @Lock(LockType.READ)
    public void doTimerWork() throws InterruptedException {
        if (!busy.compareAndSet(false, true)) {
            return;
        }
        try {
            Thread.sleep(20000L);
        } finally {
            busy.set(false);
        }
    }
}

As you can see the timer is scheduled to be triggered every five seconds. However, the method triggered in our case simulated a 20 seconds response time by call sleep() on the current Thread.

As a consequence, the container will continue to call doTimerWork() every five seconds but the condition put at the beginning of the method, busy.compareAndSet(false, true), will return immediately if the previous call has not finished. In this, we ensure that the next task will be executed only after the previous one has finished.

4. Schedule Task at a Fixed Rate

One way of doing this is to use the timer service which is injected by using @Resource and configured in the method annotated @PostConstruct. The method annotated with @Timeout will be called when the timer expires.

As mentioned in the previous article the beginning of the task execution doesn’t wait for the completion of the previous execution. This option should be used when each execution of the task is independent. The following code snippet creates a timer that fires every second:

@Startup
@Singleton
public class ProgrammaticAtFixedRateTimerBean {

    @Inject
    Event<TimerEvent> event;

    @Resource
    TimerService timerService;

    @PostConstruct
    public void initialize() {
        timerService.createTimer(0,1000, "Every second timer with no delay");
    }

    @Timeout
    public void programmaticTimout(Timer timer) {
        event.fire(new TimerEvent(timer.getInfo().toString()));
    }
}

Another way is to use @Scheduled annotation. In the following code snippet we fire a timer every five seconds:

@Startup
@Singleton
public class ScheduleTimerBean {

    @Inject
    Event<TimerEvent> event;

    @Schedule(hour = "*", minute = "*", second = "*/5", info = "Every 5 seconds timer")
    public void automaticallyScheduled(Timer timer) {
        fireEvent(timer);
    }


    private void fireEvent(Timer timer) {
        event.fire(new TimerEvent(timer.getInfo().toString()));
    }
}

5. Schedule Task with Initial Delay

If your use case scenario requires the timer to start with a delay we can do that too. In this case Jakarta EE allows the use of the timer service. Let’s have a look at an example where the timer has an initial delay of 10 seconds and then fires every five seconds:

@Startup
@Singleton
public class ProgrammaticWithInitialFixedDelayTimerBean {

    @Inject
    Event<TimerEvent> event;

    @Resource
    TimerService timerService;

    @PostConstruct
    public void initialize() {
        timerService.createTimer(10000, 5000, "Delay 10 seconds then every 5 seconds timer");
    }

    @Timeout
    public void programmaticTimout(Timer timer) {
        event.fire(new TimerEvent(timer.getInfo().toString()));
    }
}

The createTimer method used in our sample is using the following signature createTimer(long initialDuration, long intervalDuration, java.io.Serializable info) where initialDuration is the number of milliseconds that must elapse before the first timer expiration notification and intervalDuration is the number of milliseconds that must elapse between timer expiration notifications.

In this example, we’re using an initialDuration of 10 seconds and an intervalDuration of five seconds. The task will be executed for the first time after the initialDuration value and it will continue to be executed according to the intervalDuration.

6. Schedule Task Using Cron Expressions

All the schedulers that we have seen, both programmatic and automatic, allow the use of cron expressions. Let’s see an example:

@Schedules ({
   @Schedule(dayOfMonth="Last"),
   @Schedule(dayOfWeek="Fri", hour="23")
})
public void doPeriodicCleanup() { ... }

In this example the method doPeriodicCleanup() will be called every Friday at 23:00 and on the last day of the month.

7. Conclusion

In this article we have looked at various ways to schedule tasks in the Jakarta EE environment using as a starting point a previous article where samples were done using Spring.

Code samples can be found in the GitHub repository.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.