Planification à Jakarta EE

1. Vue d'ensemble

Dans un article précédent, nous avons montré comment planifier des tâches au printemps en utilisant@Scheduledannotation. Dans cet article, nous allons montrer comment réaliser la même chose en utilisant le service de minuterie dans une application Jakarta EE pour chaque cas présenté dans l'article précédent.

2. Activer la prise en charge de la planification

Dans une application Jakarta EE, il n'est pas nécessaire d'activer la prise en charge des tâches chronométrées. Le service de minuteur est un service géré par conteneur qui permet aux applications d'appeler des méthodes planifiées pour des événements temporels. Par exemple, une application peut devoir exécuter certains rapports quotidiens à une certaine heure afin de générer des statistiques.

Il existe deux types de minuteries:

  • Minuteries programmatiques : le service de minuterie peut être injecté dans n'importe quel bean (sauf un bean session avec état) et la logique métier doit être placée dans une méthode annotée avec @Timeout . Le timer peut être initialisé par une méthode annotée @PostConstruct des beans ou il peut également être initialisé simplement en appelant une méthode.
  • Timers automatiques : la logique métier est placée dans n'importe quelle méthode annotée avec @Schedule ou @Schedules . Ces minuteries sont initialisées dès le démarrage de l'application.

Commençons donc par notre premier exemple.

3. Planifier une tâche avec un délai fixe

Au printemps, cela se fait simplement en utilisant l' annotation @Scheduled (fixedDelay = 1000) . Dans ce cas, la durée entre la fin de la dernière exécution et le début de la prochaine exécution est fixe. La tâche attend toujours que la précédente soit terminée.

Faire exactement la même chose à Jakarta EE est un peu plus difficile à réaliser car il n'y a pas de mécanisme intégré similaire fourni, néanmoins, un scénario similaire peut être implémenté avec un peu de codage supplémentaire. Voyons comment cela se fait:

@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); } } }

Comme vous pouvez le voir, la minuterie est programmée pour être déclenchée toutes les cinq secondes. Cependant, la méthode déclenchée dans notre cas simulait un temps de réponse de 20 secondes en appelant sleep () sur le Thread actuel .

En conséquence, le conteneur continuera d'appeler doTimerWork () toutes les cinq secondes mais la condition placée au début de la méthode, busy.compareAndSet (false, true), reviendra immédiatement si l'appel précédent n'est pas terminé. En cela, nous nous assurons que la tâche suivante ne sera exécutée qu'après la fin de la précédente.

4. Planifier la tâche à un taux fixe

Une façon de procéder consiste à utiliser le service de minuterie qui est injecté à l'aide de @Resource et configuré dans la méthode annotée @PostConstruct . La méthode annotée avec @Timeout sera appelée à l'expiration du minuteur.

Comme mentionné dans l'article précédent, le début de l'exécution de la tâche n'attend pas la fin de l'exécution précédente. Cette option doit être utilisée lorsque chaque exécution de la tâche est indépendante. L'extrait de code suivant crée une minuterie qui se déclenche toutes les secondes:

@Startup @Singleton public class ProgrammaticAtFixedRateTimerBean { @Inject Event 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())); } }

Une autre façon consiste à utiliser l' annotation @Scheduled . Dans l'extrait de code suivant, nous déclenchons une minuterie toutes les cinq secondes:

@Startup @Singleton public class ScheduleTimerBean { @Inject Event 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. Planifier la tâche avec un délai initial

Si votre scénario d'utilisation nécessite que le minuteur démarre avec un retard, nous pouvons le faire également. Dans ce cas, Jakarta EE autorise l'utilisation du service de minuterie. Jetons un coup d'œil à un exemple où la minuterie a un délai initial de 10 secondes, puis se déclenche toutes les cinq secondes:

@Startup @Singleton public class ProgrammaticWithInitialFixedDelayTimerBean { @Inject Event 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())); } }

La méthode createTimer utilisée dans notre exemple utilise la signature suivante c reateTimer (long initialDuration, long intervalDuration, java.io.Serializable info)initialDuration est le nombre de millisecondes qui doit s'écouler avant la première notification d'expiration du minuteur et intervalDuration est le nombre de millisecondes qui doivent s'écouler entre les notifications d'expiration du minuteur.

Dans cet exemple, nous utilisons un initialDuration de 10 secondes et un intervalDuration de cinq secondes. La tâche sera exécutée pour la première fois après la valeur initialDuration et continuera à être exécutée en fonction de l' intervalleDuration .

6. Planifier la tâche à l'aide d'expressions Cron

Tous les planificateurs que nous avons vus, à la fois programmatiques et automatiques, permettent l'utilisation d'expressions cron. Voyons un exemple:

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

Dans cet exemple, la méthode doPeriodicCleanup () sera appelée tous les vendredis à 23h00 et le dernier jour du mois.

7. Conclusion

Dans cet article, nous avons examiné différentes façons de planifier des tâches dans l'environnement Jakarta EE en utilisant comme point de départ un article précédent où des exemples ont été réalisés à l'aide de Spring.

Des exemples de code peuvent être trouvés dans le référentiel GitHub.