Quartz 定时任务使用 —— 异常处理(八)

Quartz 定时任务使用

异常处理

本文根据官网示例说明Quartz在job执行异常情况时的处理。

参考官方原文:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/examples/Example6.html

本文涉及3个类:BadJob1.java、BadJob2.java 和一个调度类 JobExceptionExample.java

BadJob1.java

package com.anson.examples.example6;

import org.quartz.*;

import java.text.SimpleDateFormat;
import java.util.Date;

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class BadJob1 implements Job {

    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()));
    }

}

BadJob2.java

package com.anson.examples.example6;

import org.quartz.*;

import java.text.SimpleDateFormat;
import java.util.Date;

@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()));
    }

}

JobExceptionExample.java

package com.anson.examples.example6;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;

import static org.quartz.DateBuilder.nextGivenSecondDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * 演示 Quartz 如何处理 从job中抛出的 JobExecutionExceptions
 */
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();
    }

}

执行结果

--------------- 初始化 -------------------
badJob1 将在: 2017-09-11 18:41:30  时运行.并且重复: -1 次, 每次间隔 10 秒
badJob2 将在: 2017-09-11 18:41:30  时运行.并且重复: -1 次, 每次间隔 5 秒
[INFO] 11 九月 06:41:20.623 下午 main [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED started.
------- 开始调度 (调用.start()方法) ----------------
---group1.badJob1,执行时间:2017-09-11 18:41:30, flag: 0
--- Job1 出错!
---group1.badJob2 ,执行时间:2017-09-11 18:41:30
--- job2 出错!
[INFO] 11 九月 06:41:30.009 下午 MyScheduler_Worker-1 [org.quartz.core.JobRunShell]
Job group1.badJob1 threw a JobExecutionException: 
org.quartz.JobExecutionException: java.lang.ArithmeticException: / by zero [See nested exception: java.lang.ArithmeticException: / by zero]
	at com.anson.examples.example6.BadJob1.execute(BadJob1.java:29)
	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.anson.examples.example6.BadJob1.execute(BadJob1.java:23)
	... 2 more
[INFO] 11 九月 06:41:30.009 下午 MyScheduler_Worker-2 [org.quartz.core.JobRunShell]
Job group1.badJob2 threw a JobExecutionException: 
org.quartz.JobExecutionException: java.lang.ArithmeticException: / by zero [See nested exception: java.lang.ArithmeticException: / by zero]
	at com.anson.examples.example6.BadJob2.execute(BadJob2.java:25)
	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.anson.examples.example6.BadJob2.execute(BadJob2.java:19)
	... 2 more
---group1.badJob1,执行时间:2017-09-11 18:41:30, flag: 1
---group1.badJob1,完成时间:2017-09-11 18:41:30
---group1.badJob1,执行时间:2017-09-11 18:41:40, flag: 1
---group1.badJob1,完成时间:2017-09-11 18:41:40
---group1.badJob1,执行时间:2017-09-11 18:41:50, flag: 1
---group1.badJob1,完成时间:2017-09-11 18:41:50
---group1.badJob1,执行时间:2017-09-11 18:42:00, flag: 1
---group1.badJob1,完成时间:2017-09-11 18:42:00
---group1.badJob1,执行时间:2017-09-11 18:42:10, flag: 1
---group1.badJob1,完成时间:2017-09-11 18:42:10
---group1.badJob1,执行时间:2017-09-11 18:42:20, flag: 1
---group1.badJob1,完成时间:2017-09-11 18:42:20
[INFO] 11 九月 06:42:20.626 下午 main [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED shutting down.
[INFO] 11 九月 06:42:20.626 下午 main [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED paused.
[INFO] 11 九月 06:42:20.626 下午 main [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED shutdown complete.
~~~~~~~~~~  执行了 8 个 jobs.

说明:

job1:在抛出异常后,然后将flag设置成1,也就是说只有第一次会有异常抛出,以后都正常代码

    setRefireImmediately(true);它设置了 job 类抛出异常后的处理方式,此处意为发生异常后立即重新执行

job2:和job1不同,它没有判断,执行一次就抛出一次异常

    e2.setUnscheduleAllTriggers(true);设置了去掉它的触发器,也就意味着 BadJob2 如果发生异常,就没有机会再执行了

作业

在 job1.java 和 job2.java 中的异常如果不抛出(注释掉),会有什么结果发生呢?

job1如果不抛出:执行正常,因为在异常处理中有重启job语句

job2如果不抛出:任务每次都执行,每次都进入异常。相当于后续的任务没有停止。


未经允许请勿转载:程序喵 » Quartz 定时任务使用 —— 异常处理(八)

点  赞 (3) 打  赏
分享到: