EJB Timer vs Jakarta Scheduler
Replace heavyweight EJB timers with Jakarta Concurrency's ManagedScheduledExecutorService for simpler scheduling.
@Stateless
public class ReportGenerator {
@Resource
TimerService timerService;
@PostConstruct
public void init() {
timerService.createCalendarTimer(
new ScheduleExpression()
.hour("2").minute("0"));
}
@Timeout
public void generateReport(Timer timer) {
// runs every day at 02:00
buildDailyReport();
}
}
@ApplicationScoped
public class ReportGenerator {
@Resource
ManagedScheduledExecutorService scheduler;
@PostConstruct
public void init() {
scheduler.scheduleAtFixedRate(
this::generateReport,
0, 24, TimeUnit.HOURS);
}
public void generateReport() {
buildDailyReport();
}
}
Reduced boilerplate
No @Timeout callback or ScheduleExpression — use the standard ScheduledExecutorService API.
Better testability
Plain methods and executor mocks make unit testing straightforward without EJB container.
Cloud-native friendly
Managed executors integrate with container lifecycle and work in lightweight runtimes.
Available since Jakarta EE 10 / Concurrency 3.0
EJB timers require a @Stateless or @Singleton bean with a @Timeout callback and XML or annotation-based schedule expressions. Jakarta Concurrency provides ManagedScheduledExecutorService, which uses the familiar java.util.concurrent scheduling API. The result is less boilerplate, easier unit testing, and no EJB container dependency.