Introduction au quartz

1. Vue d’ensemble

  • http://www.quartz-scheduler.org/ est un cadre de planification de travaux open source entièrement écrit en Java et conçu pour être utilisé à la fois dans les applications J2SE et J2EE . Il offre une grande flexibilité sans sacrifier la simplicité. **

Vous pouvez créer des planifications complexes pour l’exécution de n’importe quel travail. Les exemples sont par exemple. tâches quotidiennes, tous les vendredis à 19h30 ou seulement le dernier jour de chaque mois.

Dans cet article, nous examinerons des éléments pour créer un travail avec l’API Quartz. Pour une introduction en combinaison avec Spring, nous recommandons Planification au printemps avec Quartz .

2. Dépendances Maven

Nous devons ajouter la dépendance suivante au fichier pom.xml:

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

La dernière version se trouve dans Maven. Référentiel central .

3. L’API Quartz

Le coeur du cadre est le Scheduler . Il est responsable de la gestion de l’environnement d’exécution de notre application.

Pour assurer l’évolutivité, Quartz est basé sur une architecture multithread.

  • Une fois démarré, le framework initialise un ensemble de threads de travail ** utilisés par le Scheduler pour exécuter Jobs .

Voici comment le framework peut exécuter plusieurs Jobs simultanément. Il s’appuie également sur un ensemble faiblement couplé de composants de gestion ThreadPool pour gérer l’environnement de thread.

Les interfaces clés de l’API sont:

  • Scheduler – l’API principale permettant d’interagir avec le planificateur de

le cadre ** Job – une interface à implémenter par les composants que nous souhaitons

ont exécuté ** JobDetail – utilisé pour définir les instances de __Job __s

  • Trigger – un composant qui détermine la planification sur laquelle un

donné Job sera effectuée ** JobBuilder – utilisé pour créer les instances JobDetail , qui définissent

instances de Jobs ** TriggerBuilder – utilisé pour créer des instances Trigger

Examinons chacun de ces composants.

4. Planificateur

Avant de pouvoir utiliser le Scheduler , il doit être instancié. Pour ce faire, nous pouvons utiliser la fabrique SchedulerFactory :

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();

Le cycle de vie d’un Scheduler est limité par sa création, via un SchedulerFactory et un appel à sa méthode shutdown () . Une fois créée, l’interface Scheduler peut être utilisée pour ajouter, supprimer et répertorier Jobs et Triggers , et effectuer d’autres opérations liées à la planification (telles que la suspension d’un déclencheur).

Cependant, ** le Scheduler n’agira sur les déclencheurs qu’après son démarrage avec la méthode start () :

scheduler.start();

5. Emplois

Un Job est une classe qui implémente l’interface Job . Il n’y a qu’une méthode simple:

public class SimpleJob implements Job {
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println("This is a quartz job!");
    }
}

Lorsque le déclencheur de Job’s est activé, la méthode execute () est invoquée par l’un des threads de travail du planificateur.

L’objet JobExecutionContext transmis à cette méthode fournit à l’instance de travail des informations sur son environnement d’exécution, un descripteur du Scheduler qui l’a exécuté, un descripteur de Trigger qui a déclenché l’exécution, l’objet JobDetail du travail et quelques autres éléments. .

L’objet JobDetail est créé par le client Quartz au moment où le Job est ajouté au Scheduler. Il s’agit essentiellement de la définition de l’instance de travail _: _

JobDetail job = JobBuilder.newJob(SimpleJob.class)
  .withIdentity("myJob", "group1")
  .build();

Cet objet peut également contenir divers paramètres de propriété pour Job , ainsi qu’un JobDataMap , qui peuvent être utilisés pour stocker des informations d’état pour une instance donnée de notre classe de travaux.

5.1. JobDataMap

JobDataMap est utilisé pour contenir toute quantité d’objets de données que nous souhaitons mettre à la disposition de l’instance de travail lors de son exécution. JobDataMap est une implémentation de l’interface Java Map et propose des méthodes pratiques supplémentaires pour le stockage et la récupération des données de types primitifs.

Voici un exemple d’insertion de données dans JobDataMap lors de la construction de JobDetail , avant d’ajouter le travail au planificateur:

JobDetail job = newJob(SimpleJob.class)
  .withIdentity("myJob", "group1")
  .usingJobData("jobSays", "Hello World!")
  .usingJobData("myFloatValue", 3.141f)
  .build();

Et voici un exemple montrant comment accéder à ces données lors de l’exécution du travail:

public class SimpleJob implements Job {
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();

        String jobSays = dataMap.getString("jobSays");
        float myFloatValue = dataMap.getFloat("myFloatValue");

        System.out.println("Job says: " + jobSays + ", and val is: " + myFloatValue);
    }
}

L’exemple ci-dessus affichera «Job is Hello World !, et la valeur est 3.141»

Nous pouvons également ajouter à notre classe de travail des méthodes de définition qui correspondent aux noms de clés dans JobDataMap.

Si nous le faisons, l’implémentation JobFactory par défaut de Quartz appelle automatiquement ces paramètres lors de l’instanciation du travail, évitant ainsi d’obtenir explicitement les valeurs de la carte dans notre méthode execute.

6. Déclencheurs

Les objets Trigger sont utilisés pour déclencher l’exécution de Jobs .

Lorsque nous souhaitons planifier un Job , nous devons instancier un déclencheur et en ajuster les propriétés pour configurer nos exigences de planification:

Trigger trigger = TriggerBuilder.newTrigger()
  .withIdentity("myTrigger", "group1")
  .startNow()
  .withSchedule(SimpleScheduleBuilder.simpleSchedule()
    .withIntervalInSeconds(40)
    .repeatForever())
  .build();

Un Trigger peut également être associé à un JobDataMap . Cela est utile pour transmettre à un Job des paramètres spécifiques aux exécutions du déclencheur.

Il existe différents types de déclencheurs pour différents besoins de planification.

Chacune a différentes propriétés TriggerKey pour suivre leurs identités. Cependant, certaines autres propriétés sont communes à tous les types de déclencheurs:

  • La propriété jobKey indique l’identité du travail qui devrait être

exécuté lorsque la gâchette se déclenche.

  • La propriété startTime indique à quel moment la planification du déclencheur commence

entre en vigueur. La valeur est un objet java.util.Date qui définit un moment précis pour une date donnée. Pour certains types de déclencheurs, le déclencheur est activé à l’heure de début donnée. Pour d’autres, cela marque simplement l’heure à laquelle l’horaire doit commencer.

  • La propriété endTime indique quand la planification du déclencheur doit être

annulé.

Quartz est livré avec une poignée de types de déclencheurs différents, mais les plus utilisés sont SimpleTrigger et CronTrigger .

6.1. Priorité

Parfois, lorsque nous avons plusieurs déclencheurs, Quartz peut ne pas disposer de suffisamment de ressources pour déclencher immédiatement tous les travaux sur lesquels il est prévu de les lancer en même temps. Dans ce cas, nous pouvons vouloir contrôler lequel de nos déclencheurs est disponible en premier. C’est exactement ce que la propriété priority sur un déclencheur est utilisée.

  • Par exemple ** , lorsque dix déclencheurs sont activés en même temps et que quatre threads de travail sont disponibles, les quatre premiers déclencheurs avec la priorité la plus élevée seront exécutés en premier. Lorsque nous ne définissons pas de priorité sur un déclencheur, il utilise une priorité par défaut de cinq. Toute valeur entière est autorisée en priorité, positive ou négative.

Dans l’exemple ci-dessous, nous avons deux déclencheurs avec une priorité différente. S’il n’y a pas assez de ressources pour activer tous les déclencheurs en même temps, triggerA sera le premier à être déclenché:

Trigger triggerA = TriggerBuilder.newTrigger()
  .withIdentity("triggerA", "group1")
  .startNow()
  .withPriority(15)
  .withSchedule(SimpleScheduleBuilder.simpleSchedule()
    .withIntervalInSeconds(40)
    .repeatForever())
  .build();

Trigger triggerB = TriggerBuilder.newTrigger()
  .withIdentity("triggerB", "group1")
  .startNow()
  .withPriority(10)
  .withSchedule(SimpleScheduleBuilder.simpleSchedule()
    .withIntervalInSeconds(20)
    .repeatForever())
  .build();

6.2. Raté instructions

  • Un raté se produit si un déclencheur persistant refuse son heure de déclenchement à cause de l’arrêt du Scheduler ou s’il n’ya pas de threads disponibles dans le pool de threads de Quartz. **

Les différents types de déclencheurs ont différentes instructions de ratés d’allumage disponibles. Par défaut, ils utilisent une instruction de stratégie intelligente. Lorsque le planificateur démarre, il recherche tous les déclencheurs persistants ayant échoué. Après cela, chacun d’eux est mis à jour en fonction de ses instructions de ratés d’allumage configurées individuellement.

Jetons un coup d’œil aux exemples ci-dessous:

Trigger misFiredTriggerA = TriggerBuilder.newTrigger()
  .startAt(DateUtils.addSeconds(new Date(), -10))
  .build();

Trigger misFiredTriggerB = TriggerBuilder.newTrigger()
  .startAt(DateUtils.addSeconds(new Date(), -10))
  .withSchedule(SimpleScheduleBuilder.simpleSchedule()
    .withMisfireHandlingInstructionFireNow())
  .build();

Nous avons planifié le déclencheur pour qu’il s’exécute il y a 10 secondes (il a donc 10 secondes de retard au moment de sa création) pour simuler un raté d’allumage, par exemple. parce que le planificateur était hors service ou ne disposait pas d’un nombre suffisant de threads de travail. Bien sûr, dans un scénario réel, nous ne programmerions jamais de tels déclencheurs.

Dans le premier déclencheur ( misFiredTriggerA ), aucune instruction de traitement des ratés n’est définie. Par conséquent, une règle appelée "politique intelligente" est utilisée dans ce cas et est appelée: withMisfireHandlingInstructionFireNow () . Cela signifie que le travail est exécuté immédiatement après que le planificateur a découvert le raté.

Le deuxième déclencheur définit explicitement le type de comportement auquel nous nous attendons lorsque des ratés se produisent. Dans cet exemple, il s’agit simplement de la même politique intelligente.

6.3. SimpleTrigger

  • SimpleTrigger est utilisé pour les scénarios dans lesquels nous devons exécuter un travail à un moment précis. ** Cela peut être exactement une fois ou à plusieurs reprises à des intervalles spécifiques.

Un exemple pourrait consister à déclencher une exécution de travail à 13h20 exactement à minuit le 20 janvier. De même, nous pouvons commencer à ce moment-là, puis cinq autres fois, toutes les dix secondes.

Dans le code ci-dessous, la date myStartTime a déjà été définie et permet de générer un déclencheur pour un horodatage particulier :

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
  .withIdentity("trigger1", "group1")
  .startAt(myStartTime)
  .forJob("job1", "group1")
  .build();

Ensuite, construisons un déclencheur pour un moment précis, puis répétons dix fois toutes les dix secondes:

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
  .withIdentity("trigger2", "group1")
  .startAt(myStartTime)
  .withSchedule(simpleSchedule()
    .withIntervalInSeconds(10)
    .withRepeatCount(10))
  .forJob("job1")
  .build();

6.4. CronTrigger

  • Le CronTrigger est utilisé lorsque nous avons besoin de planifications basées sur des instructions de type calendrier. ** Par exemple, nous pouvons spécifier des planifications de tir telles que very Friday à midi ou __every à 9h30.

Les expressions Cron sont utilisées pour configurer les instances de CronTrigger . Ces expressions sont constituées de chaînes de caractères composées de sept sous-expressions. Pour en savoir plus sur les expressions Cron https://docs.oracle.com/cd/E12058 01/doc/doc.1014/e12030/cron expressions.htm[here]

Dans l’exemple ci-dessous, nous construisons un déclencheur qui déclenche toutes les minutes entre 8h00 et 17h00, tous les jours:

CronTrigger trigger = TriggerBuilder.newTrigger()
  .withIdentity("trigger3", "group1")
  .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 8-17 **  **  ?"))
  .forJob("myJob", "group1")
  .build();

7. Conclusion

Dans cet article, nous avons montré comment construire un Scheduler pour déclencher un Job . Nous avons également vu certaines des options de déclenchement les plus courantes utilisées:

SimpleTrigger et CronTrigger .

Quartz peut être utilisé pour créer des planifications simples ou complexes permettant d’exécuter des dizaines, des centaines ou même davantage de tâches. Vous trouverez plus d’informations sur le cadre sur le site principal website

Le code source des exemples est disponible à l’adresse over sur GitHub .