Quartz Enterprise Scheduler: Job qui planifie lui-même
-
27-10-2019 - |
Question
J'utilise Scheduler Quartz Enterprise Job (1.8.3). La configuration de l'emploi provient de plusieurs fichiers xml et nous avons un travail spécial qui détecte les changements dans ces fichiers xml et emplois ré-horaires. Cela fonctionne dandy, mais le problème est que je dois aussi ce « travail de planificateur » pour rééchelonner lui-même. Une fois que ce travail se re-horaires, pour une raison quelconque, je vois qu'il est exécuté à plusieurs reprises. Je ne vois aucune exception, cependant.
J'ai reproduit et isolé le problème. Ce serait le point d'entrée:
public class App {
public static void main(final String[] args) throws ParseException, SchedulerException {
// get the scheduler from the factory
final Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// start the scheduler
scheduler.start();
// schedule the job to run every 20 seconds
final JobDetail jobDetail = new JobDetail("jobname", "groupname", TestJob.class);
final Trigger trigger = new CronTrigger("triggername", "groupname", "*/20 * * * * ?");
// set the scheduler in the job data map, so the job can re-configure itself
jobDetail.getJobDataMap().put("scheduler", scheduler);
// schedule job
scheduler.scheduleJob(jobDetail, trigger);
}
}
Et ce serait la classe d'emploi:
public class TestJob implements Job {
private final static Logger LOG = Logger.getLogger(TestJob.class);
private final static AtomicInteger jobExecutionCount = new AtomicInteger(0);
public void execute(final JobExecutionContext context) throws JobExecutionException {
// get the scheduler from the data map
final Scheduler scheduler = (Scheduler) context.getJobDetail().getJobDataMap().get("scheduler");
LOG.info("running job! " + jobExecutionCount.incrementAndGet());
// buid the job detail and trigger
final JobDetail jobDetail = new JobDetail("jobname", "groupname", TestJob.class);
// this time, schedule it to run every 35 secs
final Trigger trigger;
try {
trigger = new CronTrigger("triggername", "groupname", "*/50 * * * * ?");
} catch (final ParseException e) {
throw new JobExecutionException(e);
}
trigger.setJobName("jobname");
trigger.setJobGroup("groupname");
// set the scheduler in the job data map, so this job can re-configure itself
jobDetail.getJobDataMap().put("scheduler", scheduler);
try {
scheduler.rescheduleJob(trigger.getName(), jobDetail.getGroup(), trigger);
} catch (final SchedulerException e) {
throw new JobExecutionException(e);
}
}
}
Je l'ai essayé à la fois avec scheduler.rescheduleJob
et scheduler.deleteJob
scheduler.scheduleJob
alors. Peu importe ce que je fais, c'est la sortie que je reçois (j'utilise log4j):
23:22:15,874 INFO SchedulerSignalerImpl:60 - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
23:22:15,878 INFO QuartzScheduler:219 - Quartz Scheduler v.1.8.3 created.
23:22:15,883 INFO RAMJobStore:139 - RAMJobStore initialized.
23:22:15,885 INFO QuartzScheduler:241 - Scheduler meta-data: Quartz Scheduler (v1.8.3)
'MyScheduler' with instanceId '1'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
23:22:15,885 INFO StdSchedulerFactory:1275 - Quartz scheduler 'MyScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
23:22:15,886 INFO StdSchedulerFactory:1279 - Quartz scheduler version: 1.8.3
23:22:15,886 INFO QuartzScheduler:497 - Scheduler MyScheduler_$_1 started.
23:22:20,018 INFO TestJob:26 - running job! 1
23:22:50,004 INFO TestJob:26 - running job! 2
23:22:50,010 INFO TestJob:26 - running job! 3
23:22:50,014 INFO TestJob:26 - running job! 4
23:22:50,016 INFO TestJob:26 - running job! 5
...
23:22:50,999 INFO TestJob:26 - running job! 672
23:22:51,000 INFO TestJob:26 - running job! 673
Remarquez comment à 23: 22: 20018, le travail fonctionne très bien. À ce stade, les horaires de ré-emploi lui-même pour exécuter toutes les 50 secondes. La prochaine exécution (à 23: 22: 50004)., Il se prévu des centaines de fois
Toutes les idées sur la façon de configurer un emploi en l'exécution de ce travail? Qu'est-ce que je fais mal?
Merci!
La solution
facile.
Tout d'abord, vous avez un malentendu couple sur Cron expressions. "* * / 20 * * *?" est toutes les vingt secondes que le commentaire implique, mais seulement parce que 60 est divisible par 20. « / 50 ... » est pas tous les cinquante secondes. il est 0 secondes et 50 de chaque minute. Autre exemple, " / 13 ..." est secondes 0, 13, 26, 39 et 52 de chaque minute - donc entre 52 secondes et de 0 seconde, il y a seulement 8 secondes de la minute suivante, pas 13 . donc, avec * / 50 vous aurez 50 secondes entre tous les tirs, et 10 secondes entre les autres.
C'est cependant pas la cause de votre tir rapide du travail. Le problème est que le second courant est « 50 » et vous planifiez le nouveau déclencheur à feu sur la deuxième « 50 », donc immédiatement les incendies. Et puis il est encore 50 secondes, et les exécute d'emploi à nouveau, et un autre déclencheur horaires à feu sur la deuxième 50, et ainsi de suite, autant de fois que possible au cours de 50 secondes.
Vous devez définir l'heure de début de la détente dans le futur (au moins une seconde) ou il se déclenche sur la même seconde que vous planifiez, si l'horaire correspond au deuxième courant.
Aussi, si vous avez vraiment besoin de tous les « N » secondes type de programme, je suggère SimpleTrigger plutôt que CronTrigger. SimpleTrigger peut faire « toutes les 35 secondes » ou « toutes les 50 secondes » aucun problème. CronTrigger est destiné à des expressions comme « sur seconde 0, 15, 40 et 43 minutes 15 et 45 de l'heure de 10 heures tous les lundis de Janvier ».