關(guān)于任務(wù)調(diào)度框架quartz使用(異常處理,解決恢復(fù)后多次調(diào)度處理)
首先先說(shuō)說(shuō)什么是調(diào)度框架
大白話所謂的調(diào)度框架你可以把它看成一個(gè)定時(shí)任務(wù)管理框架,并且quartz框架是多線程的,
quartz最主要的三大基本特性
(1)調(diào)度器 Scheduler(控制調(diào)度)
(2)Trigger(定義觸發(fā)的條件)這里的條件 ,可以用類似于‘0/20 * * * * ?’這種表達(dá)式來(lái)表示
(3)JobDetail & Job JobDetail 定義的是任務(wù)數(shù)據(jù),而真正的執(zhí)行邏輯是在Job中
首先看以下代碼講解了如何新增了一個(gè)調(diào)度任務(wù)
QuartzEntity quartz = new QuartzEntity(); quartz.setJobName("test01"); quartz.setJobGroup("test"); quartz.setDescription("測(cè)試任務(wù)"); quartz.setJobClassName("com.itstyle.quartz.job.ChickenJob"); quartz.setCronExpression("0/20 * * * * ?"); Class cls = Class.forName(quartz.getJobClassName()) ; cls.newInstance(); //構(gòu)建job信息 JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(), quartz.getJobGroup()) .withDescription(quartz.getDescription()).build(); // 觸發(fā)時(shí)間點(diǎn) CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression()); Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger"+quartz.getJobName(), quartz.getJobGroup()) .startNow().withSchedule(cronScheduleBuilder).build(); //交由Scheduler安排觸發(fā) scheduler.scheduleJob(job, trigger);
不過(guò)這里有個(gè)問(wèn)題!,那就是調(diào)度任務(wù)停止恢復(fù)后多次調(diào)度的問(wèn)題。
如何解決,首先在properties配置一文件中配置一行代碼
org.quartz.jobStore.misfireThreshold = 5000
這里先介紹下 CronTrigger
這里有三種模式:
withMisfireHandlingInstructionDoNothing
- 不觸發(fā)立即執(zhí)行
- 等待下次Cron觸發(fā)頻率到達(dá)時(shí)刻開(kāi)始按照Cron頻率依次執(zhí)行
withMisfireHandlingInstructionIgnoreMisfires
- 以錯(cuò)過(guò)的第一個(gè)頻率時(shí)間立刻開(kāi)始執(zhí)行
- 重做錯(cuò)過(guò)的所有頻率周期后
- 當(dāng)下一次觸發(fā)頻率發(fā)生時(shí)間大于當(dāng)前時(shí)間后,再按照正常的Cron頻率依次執(zhí)行
withMisfireHandlingInstructionFireAndProceed
- 以當(dāng)前時(shí)間為觸發(fā)頻率立刻觸發(fā)一次執(zhí)行
- 然后按照Cron頻率依次執(zhí)行
我們用第一種模式,就是生成Trigger的時(shí)候添加第一種模式,以下為代碼可以參考下
QuartzEntity quartz = new QuartzEntity(); quartz.setJobName("test01"); quartz.setJobGroup("test"); quartz.setDescription("測(cè)試任務(wù)"); quartz.setJobClassName("com.itstyle.quartz.job.ChickenJob"); quartz.setCronExpression("0/20 * * * * ?"); Class cls = Class.forName(quartz.getJobClassName()) ; cls.newInstance(); //構(gòu)建job信息 JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(), quartz.getJobGroup()) .withDescription(quartz.getDescription()).build(); // 觸發(fā)時(shí)間點(diǎn) CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression()); Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger"+quartz.getJobName(), quartz.getJobGroup()) .withSchedule(cronScheduleBuilder.withMisfireHandlingInstructionDoNothing()).build(); //交由Scheduler安排觸發(fā) scheduler.scheduleJob(job, trigger);
好了,以上的方式就能解決恢復(fù)后多次調(diào)度的問(wèn)題
停止調(diào)度:
try { //quartz.getJobName() 代表任務(wù)id,quartz.getJobGroup()代表任務(wù)組 JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup()); scheduler.pauseJob(key); } catch (SchedulerException e) { e.printStackTrace(); return Result.error(); }
恢復(fù)調(diào)度:
try { //quartz.getJobName() 代表任務(wù)id,quartz.getJobGroup()代表任務(wù)組 JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup()); scheduler.resumeJob(key); } catch (SchedulerException e) { e.printStackTrace(); return Result.error(); }
刪除調(diào)度:
try { //quartz.getJobName() 代表任務(wù)id,quartz.getJobGroup()代表任務(wù)組 TriggerKey triggerKey = TriggerKey.triggerKey(quartz.getJobName(), quartz.getJobGroup()); // 停止觸發(fā)器 scheduler.pauseTrigger(triggerKey); // 移除觸發(fā)器 scheduler.unscheduleJob(triggerKey); // 刪除任務(wù) scheduler.deleteJob(JobKey.jobKey(quartz.getJobName(), quartz.getJobGroup())); System.out.println("removeJob:"+JobKey.jobKey(quartz.getJobName())); } catch (Exception e) { e.printStackTrace(); return Result.error(); }
在調(diào)度過(guò)程中出現(xiàn)異常怎么辦,如何處理
請(qǐng)看以下代碼:
/** * 實(shí)現(xiàn)序列化接口、防止重啟應(yīng)用出現(xiàn)quartz Couldn't retrieve job because a required class was not found 的問(wèn)題 */ public class TestJob extends AddXxBase implements Job,Serializable { private final static Logger LOGGER = LoggerFactory.getLogger(TestJob.class); private static final long serialVersionUID = 1L; /** * 模板 * **/ @Override public void execute(JobExecutionContext context) throws JobExecutionException { //任務(wù)調(diào)度ID String work = context.getJobDetail().getKey().getName(); try{ //定時(shí)器任務(wù)start //定時(shí)器任務(wù)end }catch (Exception e){ JobExecutionException e2 = new JobExecutionException(e); //自動(dòng)停止job相關(guān)的觸發(fā)器,job停止 //e2.setUnscheduleAllTriggers(true); //自動(dòng)任務(wù)報(bào)錯(cuò)繼續(xù)執(zhí)行 e2.setRefireImmediately(true); LOGGER.error(e2.toString()); } } }
這里分兩種有兩種方法:
//自動(dòng)停止job相關(guān)的觸發(fā)器,job停止 e2.setUnscheduleAllTriggers(true); //自動(dòng)任務(wù)報(bào)錯(cuò)繼續(xù)執(zhí)行 e2.setRefireImmediately(true);
總結(jié)
以上是關(guān)于調(diào)度任務(wù)出現(xiàn)異常后如何處理的相關(guān)代碼。
好了,這些為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用mybatis插件PageHelper實(shí)現(xiàn)分頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了使用mybatis插件PageHelper實(shí)現(xiàn)分頁(yè)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01mybatis中resultMap 標(biāo)簽的使用教程
resultMap 標(biāo)簽用來(lái)描述如何從數(shù)據(jù)庫(kù)結(jié)果集中來(lái)加載對(duì)象,這篇文章重點(diǎn)給大家介紹mybatis中resultMap 標(biāo)簽的使用,感興趣的朋友一起看看吧2018-07-07SpringBoot整合sharding-jdbc實(shí)現(xiàn)分庫(kù)分表與讀寫(xiě)分離的示例
本文主要介紹了SpringBoot整合sharding-jdbc實(shí)現(xiàn)分庫(kù)分表與讀寫(xiě)分離的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11SpringBoot整合HikariCP數(shù)據(jù)庫(kù)連接池方式
這篇文章主要介紹了SpringBoot整合HikariCP數(shù)據(jù)庫(kù)連接池方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03Java實(shí)現(xiàn)微信網(wǎng)頁(yè)授權(quán)的示例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)微信網(wǎng)頁(yè)授權(quán)的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07java基于控制臺(tái)的學(xué)生學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java基于控制臺(tái)的學(xué)生學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07Java Builder模式構(gòu)建MAP/LIST的實(shí)例講解
下面小編就為大家?guī)?lái)一篇Java Builder模式構(gòu)建MAP/LIST的實(shí)例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10