Quartz can run a lot of jobs but see how thread pools can limit how many jobs can execute simultaneously

 

示例:我们一次加载500个JOB,500个Trigger到同一个Scheduler对象中。然后再执行sched.start();

正常情况,不考虑资源时,500个任务会同时执行。但是由于我们在quartz.properties配置的org.quartz.threadPool.threadCount大小有限,所以一次只能执行线程大小的数量。正常情况会出现大量的misfire,但使用requestRecovery重新恢复执行,则不会触发misfire,会直接重新执行。

注:如果这时程序中断,而job又设置了RequestsRecovery为true,则该job会被重新执行(不受misfireThreshold影响,因为根本就不是misfire)。

可以通过JobExecutionContext.isRecovering()来判断是否是recover,因为很多时候恢复的任务要先做一些清理工作。

 

 

关于requestRecovery与misfire参考下面问答:

您好,如果我是数据库服务异常中断了一些任务,程序还在跑,当数据库服务正常后,又超过了设置的 misfireThreshold时间,那任务还会不会继续执行呢?如果不执行了那怎么处理让任务继续执行?谢谢!

如果程序正常,那job是正常执行完成(正常结束或异常结束)。

既然结束了,那就和misfireThreshold没关系了。

另外单独重新启动job吧

谢谢您的回答,重新调度这个JOB是一个方法,但是我发现我的数据服务正常后,显然超过了misfireThreshold设置时间,我没有设置RequestsRecovery属性,但任务还是可以正常运行,对于这quartz的业务流程不是很清楚,楼主怎么理解,是否可以给我详解下,谢谢。

 

就算数据库出问题了,但如果你job代码里对exception做了处理,没有导致job出错,那job运行状态就是正常的,和recovery、misfire就没关系。

比如数据库连接不上会一直重试

 

From <http://kanbol.iteye.com/blog/1129945>

 

quartz jobDetail requestRecovery

Ask Question

up vote 7 down vote favorite

The documentation for JobDetail.requestsRecovery property states the following

Instructs the Scheduler whether or not the Job should be re-executed if a 'recovery' or 'fail-over' situation is encountered.

Now, what is a 'recovery' situation or a 'fail-over' situation?

How are they different?

Does the recovery happen only if the JVM crashes during job execution or does it happen if the job execution fails because of an exception also?

 

1 Answer

active oldest votes

up vote 6 down vote

A "Recovery situation" is the generic term, one kind of recovery situation is the "fail-over".

A fail-over is a process used by fault-tolerance systems generally used with redundancy (e.g. clustering). Quartz use fail-over when is used in clustering and more Quartz "nodes" exists.

Quoting documentation:

Fail-over occurs when one of the nodes fails while in the midst of executing one or more jobs. When a node fails, the other nodes detect the condition and identify the jobs in the database that were in progress within the failed node. Any jobs marked for recovery (with the "requests recovery" property on the JobDetail) will be re-executed by the remaining nodes.

A recovery situation is every situation that produce an "Hard-shutdown" (i.e. the process it is running within crashes, or the machine is shut down).

 

To answer your second question:

  • If the JVM crashes during a job execution > Quartz will recover the job
    (Because a crash is Recovery situation)
  • if the job execution fails because of an exception > Quartz will not recover the job
    (Because exception is not an hard-shutdown, a misfire is thrown instead)

See this answer to activate recovery for your jobs.

 

From <https://stackoverflow.com/questions/19267263/quartz-jobdetail-requestrecovery>

 

 

 

quartz.properties

------------------------------------------------------------------------------------------------------------

 

#============================================================================

# Configure Main Scheduler Properties 

#============================================================================

 

org.quartz.scheduler.instanceName: TestScheduler

org.quartz.scheduler.instanceId: AUTO

 

org.quartz.scheduler.skipUpdateCheck: true

 

#============================================================================

# Configure ThreadPool 

#============================================================================

 

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool

org.quartz.threadPool.threadCount: 5

org.quartz.threadPool.threadPriority: 5

 

#============================================================================

# Configure JobStore 

#============================================================================

 

org.quartz.jobStore.misfireThreshold: 60000

 

org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

 

------------------------------------------------------------------------------------------------------------

 

------------------------------------------------------------------------------------------------------------

/*

 * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.

 *

 * Licensed under the Apache License, Version 2.0 (the "License"); you may not

 * use this file except in compliance with the License. You may obtain a copy

 * of the License at

 *

 *   http://www.apache.org/licenses/LICENSE-2.0

 *  

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

 * License for the specific language governing permissions and limitations

 * under the License.

 *

 */

 

package org.quartz.examples.example11;

 

import org.quartz.Job;

import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;

import org.quartz.JobKey;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

import java.util.Date;

 

/**

 * <p>

 * This is just a simple job that gets fired off many times by example 1

 * </p>

 *

 * @author Bill Kratzer

 */

public class SimpleJob implements Job {

 

  private static Logger      _log       = LoggerFactory.getLogger(SimpleJob.class);

 

  // job parameter

  public static final String DELAY_TIME = "delay time";

 

  /**

   * Empty constructor for job initilization

   */

  public SimpleJob() {

  }

 

  /**

   * <p>

   * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code> fires that

   * is associated with the <code>Job</code>.

   * </p>

   *

   * @throws JobExecutionException if there is an exception while executing the job.

   */

  public void execute(JobExecutionContext context) throws JobExecutionException {

 

    // This job simply prints out its job name and the

    // date and time that it is running

    JobKey jobKey = context.getJobDetail().getKey();

    _log.info("Executing job: " + jobKey + " executing at " + new Date());

 

    // wait for a period of time

    long delayTime = context.getJobDetail().getJobDataMap().getLong(DELAY_TIME);

    try {

      Thread.sleep(delayTime);

    } catch (Exception e) {

      //

    }

 

    _log.info("Finished Executing job: " + jobKey + " at " + new Date());

  }

 

}

------------------------------------------------------------------------------------------------------------

 

------------------------------------------------------------------------------------------------------------

/*

 * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.

 *

 * Licensed under the Apache License, Version 2.0 (the "License"); you may not

 * use this file except in compliance with the License. You may obtain a copy

 * of the License at

 *

 *   http://www.apache.org/licenses/LICENSE-2.0

 *  

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

 * License for the specific language governing permissions and limitations

 * under the License.

 *

 */

 

package org.quartz.examples.example11;

 

import static org.quartz.DateBuilder.futureDate;

import static org.quartz.JobBuilder.newJob;

import static org.quartz.TriggerBuilder.newTrigger;

 

import org.quartz.DateBuilder.IntervalUnit;

import org.quartz.JobDetail;

import org.quartz.Scheduler;

import org.quartz.SchedulerFactory;

import org.quartz.SchedulerMetaData;

import org.quartz.Trigger;

import org.quartz.impl.StdSchedulerFactory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

/**

 * This example will spawn a large number of jobs to run

 *

 * @author James House, Bill Kratzer

 */

public class LoadExample {

 

  private int _numberOfJobs = 500;

 

  public LoadExample(int inNumberOfJobs) {

    _numberOfJobs = inNumberOfJobs;

  }

 

  public void run() throws Exception {

    Logger log = LoggerFactory.getLogger(LoadExample.class);

 

    // First we must get a reference to a scheduler

    SchedulerFactory sf = new StdSchedulerFactory();

    Scheduler sched = sf.getScheduler();

 

    log.info("------- Initialization Complete -----------");

 

    // schedule 500 jobs to run

    for (int count = 1; count <= _numberOfJobs; count++) {

      JobDetail job = newJob(SimpleJob.class).withIdentity("job" + count, "group_1").requestRecovery() // ask scheduler

                                                                                                       // to re-execute

                                                                                                       // this job if it

                                                                                                       // was in

                                                                                                       // progress when

                                                                                                       // the scheduler

                                                                                                       // went down...

          .build();

 

      // tell the job to delay some small amount... to simulate work...

      long timeDelay = (long) (java.lang.Math.random() * 7000);

      job.getJobDataMap().put(SimpleJob.DELAY_TIME, timeDelay);

 

      Trigger trigger = newTrigger().withIdentity("trigger_" + count, "group_1")

          .startAt(futureDate((10000 + (count * 100)), IntervalUnit.MILLISECOND)) // space fire times a small bit

          .build();

 

      sched.scheduleJob(job, trigger);

      if (count % 25 == 0) {

        log.info("...scheduled " + count + " jobs");

      }

    }

 

    log.info("------- Starting Scheduler ----------------");

 

    // start the schedule

    sched.start();

 

    log.info("------- Started Scheduler -----------------");

 

    log.info("------- Waiting five minutes... -----------");

 

    // wait five minutes to give our jobs a chance to run

    try {

      Thread.sleep(300L * 1000L);

    } catch (Exception e) {

      //

    }

 

    // shut down the scheduler

    log.info("------- Shutting Down ---------------------");

    sched.shutdown(true);

    log.info("------- Shutdown Complete -----------------");

 

    SchedulerMetaData metaData = sched.getMetaData();

    log.info("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");

  }

 

  public static void main(String[] args) throws Exception {

 

    int numberOfJobs = 500;

    if (args.length == 1) {

      numberOfJobs = Integer.parseInt(args[0]);

    }

    if (args.length > 1) {

      System.out.println("Usage: java " + LoadExample.class.getName() + "[# of jobs]");

      return;

    }

    LoadExample example = new LoadExample(numberOfJobs);

    example.run();

  }

 

}

 

------------------------------------------------------------------------------------------------------------

Executing result:可以看到,因为我们的线程池只有5,所有一次只能执行5个任务,后面是执行完成一个就新增执行一个任务,使线程一直保持在5个。如果将线程池改为3,则一次直接运行3个了。

20:56:26.433 INFO  org.quartz.impl.StdSchedulerFactory 1172 instantiate - Using default implementation for ThreadExecutor

20:56:26.458 INFO  org.quartz.core.SchedulerSignalerImpl 61 <init> - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl

20:56:26.460 INFO  org.quartz.core.QuartzScheduler 240 <init> - Quartz Scheduler v.2.2.3 created.

20:56:26.461 INFO  org.quartz.simpl.RAMJobStore 155 initialize - RAMJobStore initialized.

20:56:26.462 INFO  org.quartz.core.QuartzScheduler 305 initialize - Scheduler meta-data: Quartz Scheduler (v2.2.3) 'TestScheduler' with instanceId 'NON_CLUSTERED'

  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 5 threads.

  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

 

20:56:26.463 INFO  org.quartz.impl.StdSchedulerFactory 1327 instantiate - Quartz scheduler 'TestScheduler' initialized from default resource file in Quartz package: 'quartz.properties'

20:56:26.463 INFO  org.quartz.impl.StdSchedulerFactory 1331 instantiate - Quartz scheduler version: 2.2.3

20:56:26.463 INFO  org.quartz.examples.example11.LoadExample 54 run - ------- Initialization Complete -----------

20:56:26.474 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 25 jobs

20:56:26.479 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 50 jobs

20:56:26.483 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 75 jobs

20:56:26.486 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 100 jobs

20:56:26.489 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 125 jobs

20:56:26.492 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 150 jobs

20:56:26.495 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 175 jobs

20:56:26.498 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 200 jobs

20:56:26.500 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 225 jobs

20:56:26.502 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 250 jobs

20:56:26.504 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 275 jobs

20:56:26.506 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 300 jobs

20:56:26.508 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 325 jobs

20:56:26.511 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 350 jobs

20:56:26.513 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 375 jobs

20:56:26.516 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 400 jobs

20:56:26.518 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 425 jobs

20:56:26.520 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 450 jobs

20:56:26.523 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 475 jobs

20:56:26.525 INFO  org.quartz.examples.example11.LoadExample 77 run - ...scheduled 500 jobs

20:56:26.525 INFO  org.quartz.examples.example11.LoadExample 81 run - ------- Starting Scheduler ----------------

20:56:26.526 INFO  org.quartz.core.QuartzScheduler 575 start - Scheduler TestScheduler_$_NON_CLUSTERED started.

20:56:26.527 INFO  org.quartz.examples.example11.LoadExample 86 run - ------- Started Scheduler -----------------

20:56:26.527 INFO  org.quartz.examples.example11.LoadExample 88 run - ------- Waiting five minutes... -----------

20:56:36.610 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job1 executing at Mon Aug 13 20:56:36 CST 2018

20:56:36.673 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job2 executing at Mon Aug 13 20:56:36 CST 2018

20:56:36.773 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job3 executing at Mon Aug 13 20:56:36 CST 2018

20:56:36.872 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job4 executing at Mon Aug 13 20:56:36 CST 2018

20:56:36.974 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job5 executing at Mon Aug 13 20:56:36 CST 2018

20:56:37.487 INFO  org.quartz.examples.example11.SimpleJob 72 execute - Finished Executing job: group_1.job4 at Mon Aug 13 20:56:37 CST 2018

20:56:37.495 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job6 executing at Mon Aug 13 20:56:37 CST 2018

20:56:39.444 INFO  org.quartz.examples.example11.SimpleJob 72 execute - Finished Executing job: group_1.job3 at Mon Aug 13 20:56:39 CST 2018

20:56:39.447 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job7 executing at Mon Aug 13 20:56:39 CST 2018

20:56:39.513 INFO  org.quartz.examples.example11.SimpleJob 72 execute - Finished Executing job: group_1.job7 at Mon Aug 13 20:56:39 CST 2018

20:56:39.517 INFO  org.quartz.examples.example11.SimpleJob 62 execute - Executing job: group_1.job8 executing at Mon Aug 13 20:56:39 CST 2018

20:56:40.344 INFO  org.quartz.examples.example11.SimpleJob 72 execute - Finished Executing job: group_1.job2 at Mon Aug 13 20:56:40 CST 2018

10-06 11:35