Quartz Enterprise Scheduler: Job, der sich selbst plant
-
27-10-2019 - |
Frage
Ich verwende Quartz Enterprise Job Scheduler (1.8.3). Die Jobkonfiguration stammt aus mehreren XML-Dateien, und wir haben einen speziellen Job, der Änderungen in diesen XML-Dateien und Re-Schedules-Jobs erkennt. Dies funktioniert Dandy, aber das Problem ist, dass ich diesen "Scheduler-Job" auch für die Wiederherstellung selbst benötige. Sobald dieser Job selbst neu platzt, sehe ich aus irgendeinem Grund, dass er viele Male ausgeführt wird. Ich sehe jedoch keine Ausnahmen.
Ich habe das Problem repliziert und isoliert. Dies wäre der Einstiegspunkt:
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);
}
}
Und das wäre die Jobklasse:
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);
}
}
}
Ich habe beide versucht mit scheduler.rescheduleJob
und mit scheduler.deleteJob
dann scheduler.scheduleJob
. Egal was ich tue, dies ist die Ausgabe, die ich bekomme (ich verwende 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
Beachten Sie, wie bei 23: 22: 20.018 der Job gut läuft. Zu diesem Zeitpunkt stellt sich der Job neu auf, um alle 50 Sekunden zu laufen. Wenn es das nächste Mal läuft (23: 22: 50.004), wird es hunderte Male geplant.
Alle Ideen zur Konfiguration eines Jobs während diesen Job ausführen? Was mache ich falsch?
Vielen Dank!
Lösung
Einfach.
Zunächst einmal haben Sie ein paar Missverständnisse über Cron -Ausdrücke. " */20 * * * *?" ist alle zwanzig Sekunden, wie der Kommentar impliziert, aber nur, weil 60 bis 20 gleichmäßig teilbar sind. "/50 ... "ist nicht alle fünfzig Sekunden. Es ist Sekunden 0 und 50 jeder Minute. Als ein weiteres Beispiel,"/13 ... "ist Sekunden 0, 13, 26, 39 und 52 von jeder Minute - also zwischen dem zweiten 52 und der nächsten Minute ist es nur 8 Sekunden, nicht 13. Also mit */50 Sie Sie Machen Sie zwischen jedem anderen Schuss 50 Sekunden und 10 Sekunden zwischen den anderen.
Das ist jedoch nicht die Ursache für Ihr schnelles Schuss des Jobs. Das Problem ist, dass die aktuelle Sekunde "50" ist und Sie den neuen Auslöser planen, um auf die zweite "50" zu schießen, sodass er sofort ausbreitet. Und dann ist es immer noch die zweite 50, und der Job wird erneut ausgeführt, und es plant einen weiteren Auslöser, um auf den zweiten 50 und so weiter zu schießen, so oft wie möglich in der 50. Sekunde.
Sie müssen die Startzeit des Abzugs in die Zukunft einstellen (mindestens eine Sekunde), oder es wird in derselben Sekunde, in der Sie ihn planen, abfeuern, wenn der Zeitplan mit der aktuellen Sekunde übereinstimmt.
Auch wenn Sie wirklich jeden "n" -Schloster -Zeitplan benötigen, schlage ich eher Simpligger als Crontrigger vor. Simpligger kann "alle 35 Sekunden" oder "alle 50 Sekunden" ohne Problem ausführen. Crontrigger ist für Ausdrücke wie "An Sekunden 0, 15, 40 und 43 Minuten 15 und 45 der 10 Uhr am Montag im Januar" gedacht.