1

Quartz Enterprise Job Scheduler(1.8.3)を使用しています。ジョブ構成はいくつかのxmlファイルから取得され、これらのxmlファイルの変更を検出してジョブを再スケジュールする特別なジョブがあります。これはうまく機能しますが、問題は、自分自身を再スケジュールするためにこの「スケジューラージョブ」も必要になることです。このジョブが自分自身を再スケジュールすると、何らかの理由で、何度も実行されることがわかります。ただし、例外はありません。

問題を再現して切り分けました。これがエントリポイントになります。

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

    }
}

そして、これはジョブクラスになります:

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

私はwithscheduler.rescheduleJobとwiththenの両方を試しましscheduler.deleteJobscheduler.scheduleJob。私が何をしても、これは私が得る出力です(私は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

23:22:20,018に、ジョブが正常に実行されることに注目してください。この時点で、ジョブは50秒ごとに実行されるようにスケジュールを変更します。次回の実行時(23:22:50,004)には、何百回もスケジュールされます。

そのジョブの実行中にジョブを構成する方法についてのアイデアはありますか?私は何が間違っているのですか?

ありがとう!

4

1 に答える 1

5

簡単。

まず、Cron式についていくつかの誤解があります。「*/20 * * * *?」コメントが示すように、は20秒ごとですが、60が20で割り切れるからです。「/50...」は50秒ごとではありません。毎分の0秒と50秒です。別の例として、「 / 13 ...」は毎分の秒0、13、26、39、および52です。したがって、秒52と次の分の0秒の間には、13秒ではなく8秒しかありません。 / 50は、他のすべての発砲の間に50秒、他の発砲の間に10秒かかります。

しかし、それはあなたの仕事の急速な発砲の原因ではありません。問題は、現在の秒が「50」であり、新しいトリガーが2番目の「50」で起動するようにスケジュールしているため、すぐに起動することです。そして、それはまだ2番目の50であり、ジョブは再び実行され、2番目の50で起動する別のトリガーをスケジュールし、以下同様に50秒の間に可能な限り何度も実行します。

トリガーの開始時刻を将来(少なくとも1秒)に設定する必要があります。そうしないと、スケジュールが現在の秒と一致する場合、スケジュールしているのと同じ秒にトリガーが起動します。

また、本当にすべての「N」秒タイプのスケジュールが必要な場合は、CronTriggerではなくSimpleTriggerをお勧めします。SimpleTriggerは、「35秒ごと」または「50秒ごと」に問題なく実行できます。CronTriggerは、「1月の毎週月曜日の10時の15分と45分の0、15、40、43秒」などの表現を対象としています。

于 2011-01-29T02:10:16.450 に答える