Planification des tâches avec Quartz
Introduction
Il existe plusieurs schedulers disponibles pour la plateforme java mais les plus intéressants sont Quartz et Flux. Flux est un scheduler commercial très complet, livré avec des outils de
conception et de monitoring, qui permet même de gérer des processus workflow. Quartz fait partie du projet OpenSymphony qui propose des composants orientés entreprise pour la plateforme JEE. Ce tutorial permet de découvrir les composants de base de Quartz.
conception et de monitoring, qui permet même de gérer des processus workflow. Quartz fait partie du projet OpenSymphony qui propose des composants orientés entreprise pour la plateforme JEE. Ce tutorial permet de découvrir les composants de base de Quartz.
Installation / Configuration
Vous pouvez obtenir la librairie de quartz à partir de Maven central repository.
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jboss</artifactId>
<version>1.8.4</version>
</dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jboss</artifactId>
<version>1.8.4</version>
</dependency>
La configuration de quartz est généralement effectuée par l'utilisation d'un fichier .properties, en conjonction avec l'utilisation de StdSchedulerFactory (qui utilise le fichier de configuration et instancieun scheduler). Par défaut, le StdSchedulerFactory charge le fichier nommé "quartz.properties" du répertoire de travail courant. En cas d'échouement, le fichier "quartz.properties" situé (en tant queressource) dans le pacquage org.quartz est chargé.
Le contenu du fichier "quartz.properties" est comme suit:
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = 1
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.scheduler.instanceId = 1
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
Démarrage
Il existe principalement trois types d’objets : le Scheduler (ou ordonnanceur), les Jobs et les Triggers. Un Job représente une tâche à exécuter, un Trigger représente le mécanisme de planification d’une tâche. Concernant les relations, un job peut être utilisé par plusieurs trigger, mais un trigger n’est associé qu’à un seul job.
En démarrant le scheduler, celui-ci se mettra immédiatement en attente des jobs. Pour cela on fait d’abords appel à la factory qui permet d’instancier le scheduler, puis on invoque la méthode start() sur l’instance obtenue. Le type de scheduler est déterminé par la factory en fonction des services techniques décrit dans un fichier de propriété "quartz.properties", cependant ce fichier n’est pas nécessaire si on souhaite travailler avec le scheduler par défaut.
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
Scheduler sched = sf.getScheduler();
sf.start();
Définition d’un Job
Pour créer un job avec Quartz, on doit créer une classe implémentant l'interface Job. L'interface Job comporte une méthode unique execute() où nous pourrons définir notre logique métier.Quartz passe une instance de JobExecutionContext à la méthode execute(). Cette instance de JobExecutionContext permet d'accéder aux données du contexte de l'exécution courante.
Ci-dessous une simple Job qui permet d'afficher "Hello, world"
Les instances des jobs sont gérées par Quartz, il n’est pas possible de les instancier directement. A la place, on instancie un JobDetail qui contient les information sur le Job.
Les paramètres minimums du JobDetail sont :
-définition du nom du job (qui permet d’être identifié par le scheduler)
-définition du groupe d’appartenance (pour les opérations de maintenance groupées comme la suppression ou la mise en pause d’un ensemble de tâches)
-la classe du job à exécuter.
-définition du nom du job (qui permet d’être identifié par le scheduler)
-définition du groupe d’appartenance (pour les opérations de maintenance groupées comme la suppression ou la mise en pause d’un ensemble de tâches)
-la classe du job à exécuter.
Définition d’un Trigger
Il existe actuellement deux types de Trigger :
SimpleTrigger : ce trigger simple permet des planifications d’exécution « immédiate et unique » ou récurrente avec période fixe, avec nombre de répétition limitée ou non. C’est à peu près l’équivalent du Timer de java.
Les paramètres minimums sont :
-le nom du trigger (qui permet d’être identifié par le scheduler).
-le groupe d’appartenance (pour les opérations de maintenance groupées).
Ensuite différents constructeurs permettent de définir:
- la date de début
- le nombre de répétition
- la période
SimpleTrigger : ce trigger simple permet des planifications d’exécution « immédiate et unique » ou récurrente avec période fixe, avec nombre de répétition limitée ou non. C’est à peu près l’équivalent du Timer de java.
Les paramètres minimums sont :
-le nom du trigger (qui permet d’être identifié par le scheduler).
-le groupe d’appartenance (pour les opérations de maintenance groupées).
Ensuite différents constructeurs permettent de définir:
- la date de début
- le nombre de répétition
- la période
CronTrigger : ce trigger permet des planifications basées sur les jours du calendrier. Il utilise la syntaxe des expressions cron d’Unix.
Une expression cron est un ensemble de six champs obligatoires plus un facultatif, séparés par des espaces, et pouvant êtres associés à des caractères spéciaux:
Une expression cron est un ensemble de six champs obligatoires plus un facultatif, séparés par des espaces, et pouvant êtres associés à des caractères spéciaux:
| Champs | Valeurs | Caractères spéciaux |
|---|---|---|
| Seconde | [0-59] | , - / * |
| Minute | [0-59] | , - / * |
| Heure | [0-223] | , - / * |
| Jour du mois | [1-31] | , - / * ? L W C |
| Mois | [1-12] ou {JAN,MAY, ...} | , - / * |
| Jour de la semaine | [1-7] ou {MON,WED, ...} | , - / * ? L # C |
| Année | vide ou [1970,2099] | , - / * |
Signification des caractères spéciaux :
| , | séparateur de valeurs par ex : 10, 11,12 ou JAN, MAR |
| - | intervalle entre deux valeurs par ex : 10-14 signifie 10, 11, 12, 13,14 |
| / | incrément d’une valeur de départ par ex : 0/15 correspond aux valeurs 0, 15, 30, 45. |
| * | toutes les valeurs |
| ? | permet de distinguer l’utilisation du jour du mois du jour de la semaine (c’est soit l’unsoit l’autre) |
| L | signifie le dernier du mois ou de la semaine. Si ce caractère est accompagné par un nombre (Seulement dans le cas du jour de la semaine, par exemple 6L), cela signifie le dernier X du mois avec X=1,..,7 (DIM, LUN,...). |
| W | signifie le plus proche jour de la semaine hors week-end, par ex : 10W signifie que si le 10 est un dimanche, alors l’exécution se fera le lundi. |
| # | permet de spécifier le nième jour de la semaine dans le mois, par ex : LUN#1 signifie le premier lundi du mois. |
| C | utilise le calendrier (Calendar, voir plus loin) pour définir les jours à exclure |
Exemple:
« Tous les jours du lundi au vendredi à 08h00 » se traduit par "0 0 8 ? * MON-FRI"
« Tous les derniers vendredi du mois à 10h15 » se traduit par "0 15 10 ? * 6L"
« Tous les derniers vendredi du mois à 10h15 » se traduit par "0 15 10 ? * 6L"
L'exemple ci-dessous définit un Trigger qui s'exécute chaque 5 sec à partir de la cinquième seconde après le démarrage du schedule. Ce job s'exécute chaque 18 du mois si ce n'est pas un jour férié. Si c'est le cas, il s'exécutera le jour suivant.
Calendar : interface permettant de spécifier les jours à exclure d’une planification. On utilise Calendar si la planification est basées sur des règles métiers qui ne peuvent pas être exprimées entièrement par une expression cron, par exemple les jours fériés ou les jours de repos. Il existe des implémentations tel que HolidayCalendar qui permet d’exclure des jours fériés ouWeeklyCalendar qui permet d’exclure certains jours de la semaine.
L'exemple ci-dessous permet de définir chaque mercredi comme étant un jour férié. Le job ne sera donc pas exécuté pendant ce jour.
Exemple complet utilisant Quartz
Dans ce qui suit, nous allons créer un EJB qui permet d'exécuter un Job définit dans la classe HelloEJB.java. Le projet est structuré comme suit.
Le contenu de quartz.properties ainsi que celui de HelloJob.java a été détaillé précédemment. Nous allons nous focaliser sur le code de l'EJb QuartzTest.java
Dans ce code, nous avons créé un schedular , un jobDetail que nous avons lié au Job HelloJob puis un Trigger de type cron qui démarre chaque 19 du mois et se répète chaque 5 secondes.
Nous avons considéré chaque mercredi comme étant un jour férié. Notons que nous avons passé des données à un job en utilisant un JobDataMap. Cet objet est un tableau associatif qui sera disponible dans le contexte d’exécution du Job (méthode execute).
La récupération de ces données par le Job se fait comme suit:
Références:
Jan Machacek, Aleksa Vukotic, Anirvan Chakraborty et Jessica Ditt, Pro Spring 2.5, Apress Edition, 2008, page 485
Planification de tâches en JAVA






