1. 程式人生 > >原!總結 quartz集群 定時任務 測試運行ok

原!總結 quartz集群 定時任務 測試運行ok

word cnblogs toc 訪問 job 間隔 scl nod 什麽

由於項目優化重構,想將定時任務從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">
        
        <!-- 創建同步的話單 -->
    <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" /> <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。

原!總結 quartz集群 定時任務 測試運行ok