原!总结 quartz集群 定时任务 测试运行ok
由于项目优化重构,想将定时任务从quartz单机模式变成集群或分布式的方式。于是,百度了一圈。。。。修修改改。。。用集群的方式部署定时任务,测试可以。。。
集群?分布式?什么区别?
集群:同一个业务,部署在多个服务器上
分布式:一个业务分拆多个子业务,部署在不同的服务器上
或者说
集群:是指在多台不同的服务器中部署相同应用或服务模块,构成一个集群,通过负载均衡设备对外提供服务。
分布式:是指在多台不同的服务器中部署不同的服务模块,通过远程调用协同工作,对外提供服务。
平时常用的quartz单机模式
缺点:
1.单台server如果挂太多定时任务,负载太重,若一个应用部署在两台或多台server上,而定时任务只在一台运行,资源没有合理优化使用。(没有负载均衡)
2.若运行定时任务的某台server挂了,那么定时任务就不能进行下去,会影响后期业务发展。(没有failover-失效转移策略)
3.且不说server挂了,如果是运行某个定时任务的线程或相关的某进程非正常退出时(比如进程崩溃,机器断电等),在server恢复后,不会继续执行该task,也会影响业务。
优点:
1.实现方便,快捷,能满足一般的定时任务需求。
2.job信息默认存储在内存中,访问快,性能佳。
(Quartz提供两种基本作业存储类型。第一种类型叫做RAMJobStore,第二种类型叫做JDBC作业存储。)
主要原因是平时常用的quartz存储类型是RAMJobStore,在默认情况下Quartz将任务调度的运行信息保存在内存中,这种方法提供了最佳的性能,因为内存中数据访问最快。不足之处是缺乏数据的持久性,当程序路途停止或系统崩溃时,所有运行的信息都会丢失。
但是单机模式,如果自己写代码,把job是持久化到数据库中,应该也能实现上面的一些控制。
--------------------------------------我目前的quartz 集群 定时任务----------------------------------------------------
jdk版本:1.8.0_91
quartz版本:1.8.6 ---- 要到官网下载对应的表 quartz-1.8.6.tar\quartz-1.8.6\docs\dbTables\
spring版本:3.2.3
mysql版本:5.1.73
关于quartz的一些基本概念,就不说了,网上很多。quartz集群原理简单说下吧:
1.job要持久化到数据库,因为多台server部署了quartz,是通过同一个数据库的job信息进行感知job的执行情况,因此要有相关的 QRTZ_* 的表来存储这些信息,quartz官网中找
,比如我的quartz是1.8.6,则要去官网中找相应的版本的表,tables_mysql_innodb.sql (我的是mysql数据库,innodb数据库引擎 )。
2.多台server的quartz调度器都是尽最大努力去执行job,通过QRTZ_LOCKS 来锁定job,实现同步机制。(quartz1.8.6版本 QRTZ_LOCKS表 有5条记录:CALENDAR_ACCESS, JOB_ACCESS ,MISFIRE_ACCESS ,STATE_ACCESS ,TRIGGER_ACCESS)
关于行锁的机制:
1、mysql > set autocommit=0; //先把mysql设置为不自动提交。
2、 select * from es_locks where lock_name = 'TRIGGER_ACCESS' for update ; //线程一通过for update 可以把这行锁住
3、 select * from es_locks where lock_name = 'TRIGGER_ACCESS' for update ; //线程二通过for update 无法获得锁,线程等待。
4、commit; //线程一通过commit 释放锁
5、 //线程二可以访问到数据,线程不再等待。
所以,通过这个机制,一次只能有一个线程来操作 加锁 - 操作 - 释放锁。 如果 操作 的时间过长的话,会带来集群间的主线程等待。
数据库行锁是一种悲观锁,锁表时其它线程无法查询。
原博文地址:http://blog.csdn.net/guolong1983811/article/details/51501366
quartz定时任务主要是三块东西:1.job 2.trigger 3.schedule + quartz数据源的配置
直接上代码
1.applicationContext-quartz.xml中job的配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 创建同步的话单 MethodInvokingJobDetailFactoryBean不支持序列化,所以用JobDetailBean --> <bean id="createBbossCdrFileTimerJob" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="com.cmcc.open.mssportal.util.MyDetailQuartzJobBean"></property> <property name="jobDataAsMap"> <map> <entry key="targetObject" value="createBbossCdrFileTask" /> <!-- 普通java类 CreateBbossCdrFileTask 记得要注入spring容器 --> <entry key="targetMethod" value="createBbossCdrFile" /> <!-- 上面类中的定时任务方法 public void createBbossCdrFile() --> </map> </property> <!-- 是否store,当没有trigger关联时 ,默认false --> <!-- <property name="durability" value="true" /> --> <!-- requestsRecovery属性设置为 true,当Quartz服务被中止后,再次启动或集群中其他机器接手任务时会尝试恢复执行之前未完成的所有任务。 --> <!-- <property name="requestsRecovery" value="true" /> 若这个为true,则若job执行的进程中断或崩溃,不包括抛出异常,调度器检测到会重新开启执行该job
(与org.quartz.jobStore.misfireThreshold设置无关) --> </bean> <!-- misfire处理策略 默认:MISFIRE_INSTRUCTION_SMART_POLICY=0 MISFIRE_INSTRUCTION_FIRE_ONCE_NOW=1 MISFIRE_INSTRUCTION_DO_NOTHING=2 --> <bean id="createBbossCdrFileTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="createBbossCdrFileTimerJob"></property> <property name="cronExpression" value="0/15 * * * * ?"></property> <property name="misfireInstruction" value="2"></property> </bean> <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="applicationContextSchedulerContextKey" value="applicationContext"></property> <property name="configLocation" value="classpath:quartz.properties" />
<!-- 需要overwrite已经存在的job,如果需要动态的修改已经存在的job,就需要设置为true,否则会以数据库中已经存在的为准 -->
<property name="overwriteExistingJobs" value="true" /> <property name="triggers"> <list> <ref bean="callRecordsTimerServiceTrigger"/> </list> </property> </bean> </beans>
其中 dataSource 我是配置在 applicationContext.xml中了
applicationContext.xml
<!-- 数据库配置文件位置 --> <context:property-placeholder location="classpath:datasource.properties" /> //配置在datasource.properties文件中,通过这个引入 <!-- 配置dbcp数据源 ,其中jdbc相关属性配置在了另外一个配置文件中,在这引用--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- 队列中的最小等待数 --> <property name="minIdle" value="${jdbc.minIdle}"></property> <!-- 队列中的最大等待数 --> <property name="maxIdle" value="${jdbc.maxIdle}"></property> <!-- 最长等待时间,单位毫秒 --> <property name="maxWait" value="${jdbc.maxWait}"></property> <!-- 最大活跃数 --> <property name="maxActive" value="${jdbc.maxActive}"></property> <property name="initialSize" value="${jdbc.initialSize}"></property> <property name="timeBetweenEvictionRunsMillis" value="86400"></property> <property name="testWhileIdle" value="true"></property> <property name="validationQuery" value="SELECT 1 FROM dual"></property> </bean>
其中 com.cmcc.open.mssportal.util.MyDetailQuartzJobBean
/* * Project: zhejiang-refactor-open manager Webapp * * File Created at 2017年8月23日 * * Copyright 2016 CMCC Corporation Limited. * All rights reserved. * * This software is the confidential and proprietary information of * ZYHY Company. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license. */ package com.cmcc.open.mssportal.util; import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.StatefulJob; import org.springframework.context.ApplicationContext; import org.springframework.scheduling.quartz.QuartzJobBean; /** * @Type MyDetailQuartzJobBean.java * @Desc * @author * @date 2017年8月23日 上午10:22:38 * @version */ //实现StatefulJob接口,成为有状态的job,使Job不能并发执行 <==>相当于 常用的quartz配置 concurrent=false public class MyDetailQuartzJobBean extends QuartzJobBean /* implements StatefulJob */ { protected final Log logger = LogFactory.getLog(getClass()); private String targetObject; private String targetMethod; private ApplicationContext ctx; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { try { logger.info("execute [" + targetObject + "] at once>>>>>>"); Object otargetObject = ctx.getBean(targetObject); Method m = null; try { m = otargetObject.getClass().getMethod(targetMethod, new Class[] {}); m.invoke(otargetObject, new Object[] {}); } catch (SecurityException e) { e.printStackTrace(); logger.error("-----MyDetailQuartzJobBean SecurityException" + e.getMessage(), e); } catch (NoSuchMethodException e) { e.printStackTrace(); logger.error("-----MyDetailQuartzJobBean NoSuchMethodException" + e.getMessage(), e); } } catch (Exception e) { throw new JobExecutionException(e); } } public void setApplicationContext(ApplicationContext applicationContext) { this.ctx = applicationContext; } public void setTargetObject(String targetObject) { this.targetObject = targetObject; } public void setTargetMethod(String targetMethod) { this.targetMethod = targetMethod; } }
2.quartz.properties 配置如下
#Configure Main Scheduler Properties
#调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName = TestScheduler1
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId = AUTO
#Configure ThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
#自创建父线程
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
#org.quartz.plugin.shutdownhook.cleanShutdown = true
#Configure JobStore
#容许的最大作业延,若任务延迟时间超过该设定值,就被认为是misfire了,然后会执行关联的misfire策略(trigger中配置), 默认60s
org.quartz.jobStore.misfireThreshold = 1000
#数据保存方式为持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
#打开集群模式
org.quartz.jobStore.isClustered = true
#调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval = 20000
spring配置就不说了,配置文件都要读进去,启动两台tomcat(修改另外一台tomcat的三个端口),不然启动会报错。
tomcat1 tomcat2
admin 8005 8085
http 8080 8088
ajp 8009 8089
测试现象
1.启动两台tomcat,两台都会执行不同的job。(同一个job只会在一台tomcat上执行)
2.关了其中一台,另外一台会执行所有的job。(上面配置文件applicationContext-quartz.xml中我只配置了一个job,测试的时候我配了多个job)
3.再启动刚刚关闭的那台tomcat,定时任务又会分配过来执行(很大概率会分配过来)。
4.若在某台tomcat在执行job时,把它强制关了(job没执行完),并且如果这个job设置了requestsRecovery=true,那么另外一台会检测到,然后重新执行该job。
最后谈谈 quartz.properties 中的 org.quartz.jobStore.misfireThreshold设置
理解成 “容许的最大作业延“,我觉得好理解,就是说,如果说某个定时任务的延迟时间,超过了该值,则会被认为是misfire(错过触发)了,紧着会执行相应的misfire策略,quartz1.8.6中有三种策略:
misfire处理策略 默认:MISFIRE_INSTRUCTION_SMART_POLICY=0 //默认的策略 MISFIRE_INSTRUCTION_FIRE_ONCE_NOW=1 //fire once now 马上触发一次 MISFIRE_INSTRUCTION_DO_NOTHING=2 //do nothing 不处理
日志分析
(下面的测试 都是MyDetailQuartzJobBean 没有实现 StatefulJob接口,换句话说,都是无状态的job,定时任务可以并发执行)
案例1
quartz1.8.6版本
每隔15秒 执行定时任务 定时任务要执行20s
设置misfirethreshold =2000ms 线程池:线程数量设置为1
默认的quartz misfire处理策略---MISFIRE_INSTRUCTION_SMART_POLICY
[scheduler_Worker-1] 2017-08-24 16:50:00 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:50:00 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:50:00
[QuartzScheduler_scheduler-huamao-HP1503564598330_MisfireHandler] 2017-08-24 16:50:18 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
[scheduler_Worker-1] 2017-08-24 16:50:20 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 16:50:20
[scheduler_Worker-1] 2017-08-24 16:50:20 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:50:20 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:50:20
[QuartzScheduler_scheduler-huamao-HP1503564598330_MisfireHandler] 2017-08-24 16:50:32 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
[QuartzScheduler_scheduler-huamao-HP1503564598330_MisfireHandler] 2017-08-24 16:50:36 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
[scheduler_Worker-1] 2017-08-24 16:50:40 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 16:50:40
[QuartzScheduler_scheduler-huamao-HP1503564598330_MisfireHandler] 2017-08-24 16:50:40 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
[scheduler_Worker-1] 2017-08-24 16:50:40 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:50:40 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:50:40
[QuartzScheduler_scheduler-huamao-HP1503564598330_MisfireHandler] 2017-08-24 16:50:48 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
[QuartzScheduler_scheduler-huamao-HP1503564598330_MisfireHandler] 2017-08-24 16:50:52 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
2017-08-24 16:50:00 -- 2017-08-24 16:50:20
2017-08-24 16:50:15 (这个定时任务 延迟了5s > 设定的misfirethreshold =2s, 被认为misfire了,所以该任务实际执行开始时间为2017-08-24 16:50:20 )
案例2
其他参数同案例1一样
设置misfirethreshold 2000000ms (设置大一点)
[scheduler_Worker-1] 2017-08-24 16:56:45 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:56:45 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:56:45
[scheduler_Worker-1] 2017-08-24 16:57:05 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 16:57:05
[scheduler_Worker-1] 2017-08-24 16:57:05 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:57:05 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:57:05
[scheduler_Worker-1] 2017-08-24 16:57:25 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 16:57:25
[scheduler_Worker-1] 2017-08-24 16:57:25 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:57:25 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:57:25
[scheduler_Worker-1] 2017-08-24 16:57:45 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 16:57:45
[scheduler_Worker-1] 2017-08-24 16:57:45 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:57:45 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:57:45
[scheduler_Worker-1] 2017-08-24 16:58:05 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 16:58:05
[scheduler_Worker-1] 2017-08-24 16:58:06 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 16:58:06 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 16:58:06
[scheduler_Worker-1] 2017-08-24 16:58:26 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 16:58:26
2017-08-24 16:56:45 -- 2017-08-24 16:57:05 实际 预期 2017-08-24 16:56:45 -- 2017-08-24 16:57:05 || 2017-08-24 16:57:00 -- 2017-08-24 16:57:20
2017-08-24 16:57:05 -- 2017-08-24 16:57:25
原来打算 开始
2017-08-24 16:56:45
2017-08-24 16:57:00
2017-08-24 16:57:15
但是只有一个线程,虽然没有misfire,但是好像是尽最大努力执行
案例3
其他同案例1不变 (产生misfire 用 MISFIRE_INSTRUCTION_DO_NOTHING 策略测试)
trigger的misfire 处理策略
<!-- <property name="misfireInstruction" value="2"></property> -->
<property name="misfireInstructionName" value="MISFIRE_INSTRUCTION_DO_NOTHING"></property>
[scheduler_Worker-1] 2017-08-24 17:32:45 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 17:32:45 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 17:32:45
[QuartzScheduler_scheduler-huamao-HP1503567162825_MisfireHandler] 2017-08-24 17:33:03 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
[scheduler_Worker-1] 2017-08-24 17:33:05 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 17:33:05
[scheduler_Worker-1] 2017-08-24 17:33:15 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 17:33:15 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 17:33:15
[QuartzScheduler_scheduler-huamao-HP1503567162825_MisfireHandler] 2017-08-24 17:33:33 INFO -org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:963) - Handling 1 trigger(s) that missed their scheduled fire-time.
[scheduler_Worker-1] 2017-08-24 17:33:35 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:96) - ---------createBbossCdrFile task end----------2017-08-24 17:33:35
[scheduler_Worker-1] 2017-08-24 17:33:45 INFO -com.cmcc.open.mssportal.util.MyDetailQuartzJobBean.executeInternal(MyDetailQuartzJobBean.java:42) - execute [createBbossCdrFileTask] at once>>>>>>
[scheduler_Worker-1] 2017-08-24 17:33:45 INFO -com.cmcc.open.ss.timer.service.CreateBbossCdrFileTask.createBbossCdrFile(CreateBbossCdrFileTask.java:86) - ---------createBbossCdrFile task begin----------2017-08-24 17:33:45
预期执行 实际执行
2017-08-24 17:32:45 2017-08-24 17:32:45 -- 2017-08-24 17:33:05
2017-08-24 17:33:00 --> 这个错过啦 因为misfire策略设置donothing ,所以跳过该任务
2017-08-24 17:33:15 --> 开始执行这个
2017-08-24 17:33:30
刚好是按照cron时间表达式实行
案例4
如果 线程池:线程数量设置为10,那么会起来多个线程去执行该job
2017-08-24 17:32:45 线程1执行
2017-08-24 17:33:00 线程2执行
2017-08-24 17:33:15 线程3执行
2017-08-24 17:33:30 线程xxx执行 并不会misfire
案例5
设置:每隔15s执行 定时任务要执行20s(定时任务会超时)
为了防止任务并发,MyDetailQuartzJobBean 实现 StatefulJob接口,使之成为有状态的job
测试结果:
job只有一个线程去一个一个执行,不会并发。如果定时任务预期的执行时间 超时了,但是没有misfire,结果的执行策略是:尽最大努力执行的状态,一个执行完,马上执行下一个
如果超时了,并且超时时间大于org.quartz.jobStore.misfireThreshold的设置,即 misfire了,会执行相应的misfire策略。(若是donothing策略,则完全等价于 concurrent=false的设置)
我们平时常用的非集群,配置 concurrent=false,job不会并发,若是有个定时任务超时了,那就超时的这个任务就不会执行了,只会在按照cron时间表达式 继续执行下一个job。