概述
我们根据官网示例说明Quartz在job执行异常情况时的处理。
参考官方原文:
http://www.quartz-scheduler.org/documentation/quartz-2.2.x/examples/Example6.html
本文涉及3个类:
BadJob1.java、
BadJob2.java
一个调度类 JobExceptionExample.java
示例
package com.xgj.quartz.quartzItself.exception; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.PersistJobDataAfterExecution; /** * * * @ClassName: BadJob1 * * @Description: setRefireImmediately * * @author: Mr.Yang * * @date: 2017年11月15日 上午1:10:17 */ @PersistJobDataAfterExecution @DisallowConcurrentExecution public class BadJob1 implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); JobKey jobKey = context.getJobDetail().getKey(); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); int flag = dataMap.getInt("flag"); System.out.println("---" + jobKey + ",执行时间:" + dateFormat.format(new Date()) + ", flag: " + flag); // 由于零错误除以此作业将生成的异常的例外(仅在第一次运行) try { int result = 4815 / flag; } catch (Exception e) { System.out.println("--- Job1 出错!"); // 修复分母,所以下次这个作业运行它不会再失败 JobExecutionException e2 = new JobExecutionException(e); dataMap.put("flag", "1"); // 这个工作会立即重新启动 e2.setRefireImmediately(true); throw e2; } System.out.println("---" + jobKey + ",完成时间:" + dateFormat.format(new Date())); } }
package com.xgj.quartz.quartzItself.exception; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.PersistJobDataAfterExecution; /** * * * @ClassName: BadJob2 * * @Description: setUnscheduleAllTriggers * * @author: Mr.Yang * * @date: 2017年11月15日 上午1:10:24 */ @PersistJobDataAfterExecution @DisallowConcurrentExecution public class BadJob2 implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); JobKey jobKey = context.getJobDetail().getKey(); System.out.println("---" + jobKey + " ,执行时间:" + dateFormat.format(new Date())); try { int result = 4815 / 0; } catch (Exception e) { System.out.println("--- job2 出错!"); // Quartz将自动取消与此作业相关联的所有触发器,以使其不再运行 JobExecutionException e2 = new JobExecutionException(e); e2.setUnscheduleAllTriggers(true); throw e2; } System.out.println("---" + jobKey + ",完成时间:" + dateFormat.format(new Date())); } }
package com.xgj.quartz.quartzItself.exception; import static org.quartz.DateBuilder.nextGivenSecondDate; import static org.quartz.JobBuilder.newJob; import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import static org.quartz.TriggerBuilder.newTrigger; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.SchedulerMetaData; import org.quartz.SimpleTrigger; import org.quartz.impl.StdSchedulerFactory; /** * * * @ClassName: JobExceptionExample * * @Description: 演示 Quartz 如何处理 从job中抛出的 JobExecutionExceptions * * @author: Mr.Yang * * @date: 2017年11月15日 上午1:10:02 */ public class JobExceptionExample { public void run() throws Exception { // 任务执行的时间 格式化 SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); System.out.println("--------------- 初始化 -------------------"); // 下一个15秒 Date startTime = nextGivenSecondDate(null, 15); // badJob1 每10s执行一次 , 抛出异常,并立即重新执行 JobDetail job = newJob(BadJob1.class).withIdentity("badJob1", "group1") .usingJobData("flag", "0").build(); SimpleTrigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInSeconds(10) .repeatForever()).build(); Date ft = sched.scheduleJob(job, trigger); System.out.println(job.getKey().getName() + " 将在: " + dateFormat.format(ft) + " 时运行.并且重复: " + trigger.getRepeatCount() + " 次, 每次间隔 " + trigger.getRepeatInterval() / 1000 + " 秒"); // badJob2 每5秒执行一次 , 并且 会抛出异常,然后 不再执行 job = newJob(BadJob2.class).withIdentity("badJob2", "group1").build(); trigger = newTrigger() .withIdentity("trigger2", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInSeconds(5) .repeatForever()).build(); ft = sched.scheduleJob(job, trigger); System.out.println(job.getKey().getName() + " 将在: " + dateFormat.format(ft) + " 时运行.并且重复: " + trigger.getRepeatCount() + " 次, 每次间隔 " + trigger.getRepeatInterval() / 1000 + " 秒"); sched.start(); System.out.println("------- 开始调度 (调用.start()方法) ----------------"); try { // 睡眠 30s Thread.sleep(60L * 1000L); } catch (Exception e) { } sched.shutdown(false); // 显示一下 已经执行的任务信息 SchedulerMetaData metaData = sched.getMetaData(); System.out.println("~~~~~~~~~~ 执行了 " + metaData.getNumberOfJobsExecuted() + " 个 jobs."); } public static void main(String[] args) throws Exception { JobExceptionExample example = new JobExceptionExample(); example.run(); } }
运行结果
INFO StdSchedulerFactory - Using default implementation for ThreadExecutor INFO SimpleThreadPool - Job execution threads will use class loader of thread: main INFO SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl INFO QuartzScheduler - Quartz Scheduler v.2.2.3 created. INFO RAMJobStore - RAMJobStore initialized. INFO QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.3) 'DefaultQuartzScheduler' 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 10 threads. Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. INFO StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties' INFO StdSchedulerFactory - Quartz scheduler version: 2.2.3 --------------- 初始化 ------------------- badJob1 将在: 2017-11-15 01:14:15 时运行.并且重复: -1 次, 每次间隔 10 秒 badJob2 将在: 2017-11-15 01:14:15 时运行.并且重复: -1 次, 每次间隔 5 秒 INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started. ------- 开始调度 (调用.start()方法) ---------------- ---group1.badJob1,执行时间:2017-11-15 01:14:15, flag: 0 --- Job1 出错! ---group1.badJob2 ,执行时间:2017-11-15 01:14:15 --- job2 出错! INFO JobRunShell - Job group1.badJob1 threw a JobExecutionException: org.quartz.JobExecutionException: java.lang.ArithmeticException: / by zero at com.xgj.quartz.quartzItself.exception.BadJob1.execute(BadJob1.java:51) at org.quartz.core.JobRunShell.run(JobRunShell.java:202) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) Caused by: java.lang.ArithmeticException: / by zero at com.xgj.quartz.quartzItself.exception.BadJob1.execute(BadJob1.java:45) ... 2 common frames omitted INFO JobRunShell - Job group1.badJob2 threw a JobExecutionException: org.quartz.JobExecutionException: java.lang.ArithmeticException: / by zero at com.xgj.quartz.quartzItself.exception.BadJob2.execute(BadJob2.java:44) at org.quartz.core.JobRunShell.run(JobRunShell.java:202) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) Caused by: java.lang.ArithmeticException: / by zero at com.xgj.quartz.quartzItself.exception.BadJob2.execute(BadJob2.java:38) ... 2 common frames omitted ---group1.badJob1,执行时间:2017-11-15 01:14:15, flag: 1 ---group1.badJob1,完成时间:2017-11-15 01:14:15 ---group1.badJob1,执行时间:2017-11-15 01:14:25, flag: 1 ---group1.badJob1,完成时间:2017-11-15 01:14:25 ---group1.badJob1,执行时间:2017-11-15 01:14:35, flag: 1 ---group1.badJob1,完成时间:2017-11-15 01:14:35 ---group1.badJob1,执行时间:2017-11-15 01:14:45, flag: 1 ---group1.badJob1,完成时间:2017-11-15 01:14:45 ---group1.badJob1,执行时间:2017-11-15 01:14:55, flag: 1 ---group1.badJob1,完成时间:2017-11-15 01:14:55 ---group1.badJob1,执行时间:2017-11-15 01:15:05, flag: 1 ---group1.badJob1,完成时间:2017-11-15 01:15:05 INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down. INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused. INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete. ~~~~~~~~~~ 执行了 8 个 jobs.
示例说明
job1:在抛出异常后,然后将flag设置成1,也就是说只有第一次会有异常抛出,以后都正常代码
setRefireImmediately(true);它设置了 job 类抛出异常后的处理方式,此处意为发生异常后立即重新执行
job2:和job1不同,它没有判断,执行一次就抛出一次异常
e2.setUnscheduleAllTriggers(true);设置了去掉它的触发器,也就意味着 BadJob2 如果发生异常,就没有机会再执行了
说明
在 job1.java 和 job2.java 中的异常如果不抛出(注释掉),会有什么结果发生呢?
// throw e2;-- 注释掉这一行后执行
job1如果不抛出:执行正常,因为在异常处理中有重启job语句
job2如果不抛出:任务每次都执行,每次都进入异常。相当于后续的任务没有停止。
示例源码
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster