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