Quartz超时重试机制

      高可用作为考究系统的一项重要指标,如何做到系统的高可用,谈及一个系统,这个话题就难以越过。Quartz作为目前调度框架的一个流行组件,如何保证Quartz的高可用,任务调度失败后,如何进行重试,这个也是一个值得关注的问题。

      网上看过许多涉及定时调度的开源项目,但发现其都存在一个问题,并未对任务调度的失败做处理,仅仅只是简单的日志记录,以及手工重采。但是现实情况中,往往可能因为间歇性原因导致调度的失败,可能重新调度一下就可以成功,那么这时失败重试就尤为重要。

      找过网上关于Quartz失败后如何实现重试。倒是找到过集中方式。

  1. 引入第三方jar包,spring-retry。可以通过注解的方式或者集成对应的类,重写对应的方法。个人观点。又引入第三方jar,感觉不太理性。同时感觉过于复杂,有的业务需求不太好控制。
  2. 在Quartz里面抛异常时,自己用线程类睡多长时间后,进行再次调用。这种存在很大缺点。线程一直阻塞,不太优雅。当然可以用线程池的方式来进行实现,这种我没尝试过。
  3. Quartz抛异常时,获取失败的job,设置启动时间,策略执行一次,这种方式,个人觉得最好,够优雅

下面简单介绍一下这种方式,直接贴源码:

public abstract class AbstractQuartzJob implements Job
{
    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);

    @Override
    public void execute(JobExecutionContext context) {
        ParamMap<String, Object> sysJob = (ParamMap<String, Object>) context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES);

        try
        {
            JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
            if(!jobDataMap.containsKey("currRetryCount")) {
                before(context, sysJob);
            }
            if (sysJob != null)
            {
                doExecute(context, sysJob);
            }
            afterReturning(context, sysJob);
        } catch (Exception e)
        {
            afterThrowing(context, e, sysJob);
        }
    }

    /**
     * @description
     *      在抛出异常后
     * @Date        2019/6/28 15:57
     * @Author      wangzx
     * @Version     V1.0.20
     **/
    protected void afterThrowing(JobExecutionContext context, Exception e, ParamMap<String, Object> sysJob) {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        int maxRetryCount = Integer.parseInt(YmlUtils.getValue("schedule.maxAttempt").toString());
        long retryInterval = Long.parseLong(YmlUtils.getValue("schedule.delay")) * 60 * 1000;
        ParamMap<String, Object> paramMap = new ParamMap<>();

        int currRetryCount = jobDataMap.containsKey("currRetryCount") ? jobDataMap.getIntValue("currRetryCount") : 0;
        if(currRetryCount < maxRetryCount) {
            jobDataMap.put("currRetryCount", currRetryCount + 1);

            JobDetail job = context
                    .getJobDetail()
                    .getJobBuilder()
                    .withIdentity(context.getJobDetail().getKey().getName() + "_" + currRetryCount, "FailingJobsGroup")
                    .usingJobData(jobDataMap)
                    .build();

            OperableTrigger trigger = (OperableTrigger) TriggerBuilder
                    .newTrigger()
                    .forJob(job)
                    .startAt(new Date(context.getFireTime().getTime() + retryInterval))
                    .build();

            try {
                context.getScheduler().scheduleJob(job, trigger);
            } catch (SchedulerException e1) {
                e1.printStackTrace();
            }
            paramMap.put("motTaskStatus", "1");
            paramMap.put("motTaskId", sysJob.get("motTaskId"));
            SpringUtils.getBean(F051_F100_IMotTaskDao.class).f2106054(paramMap);
        } else {
            log.error("任务执行异常:", e);
            after(context, e, sysJob);

            paramMap.put("motTaskStatus", "3");
            String currDateStr = DateUtil.format(new Date(), "yyyyMMdd HHmmss");
            String[] strs = currDateStr.split(" ");
            String beginTime = strs[1];
            paramMap.put("endTime", beginTime);
            paramMap.put("motTaskId", sysJob.get("motTaskId"));
            // 写入数据库当中
            SpringUtils.getBean(F051_F100_IMotTaskDao.class).f2106054(paramMap);
        }
    }

    /**
     * @description
     *      返回后
     * @Date        2019/6/28 16:01
     * @Author      wangzx
     * @Version     V1.0.20
     **/
    protected void afterReturning(JobExecutionContext context, ParamMap<String, Object> sysJob) {
        String currDateStr = DateUtil.format(new Date(), "yyyyMMdd HHmmss");
        String[] strs = currDateStr.split(" ");
        String beginTime = strs[1];

        ParamMap<String, Object> paramMap = new ParamMap<>();
        paramMap.put("endTime", beginTime);
        paramMap.put("motTaskStatus", "2");
        paramMap.put("motTaskId", sysJob.get("motTaskId"));

        // 写入数据库当中
        SpringUtils.getBean(F051_F100_IMotTaskDao.class).f2106054(paramMap);
    }

    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     */
    protected void before(JobExecutionContext context, ParamMap<String, Object> sysJob)
    {
        String currDateStr = DateUtil.format(new Date(), "yyyyMMdd HHmmss");
        String[] strs = currDateStr.split(" ");
        String currDate = strs[0];
        String beginTime = strs[1];
        ParamMap<String, Object> paramMap = new ParamMap<>();
        paramMap.put("currDate", currDate);
        paramMap.put("beginTime", beginTime);
        paramMap.put("motTaskId", sysJob.get("motTaskId"));

        // 写入数据库当中
        SpringUtils.getBean(F051_F100_IMotTaskDao.class).f2106054(paramMap);
    }

    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     */
    protected void after(JobExecutionContext context, Exception e, ParamMap<String, Object> sysJob) {
    }

    /**
     * 执行方法,由子类重载
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     * @throws Exception 执行过程中的异常
     */
    protected abstract void doExecute(JobExecutionContext context, ParamMap<String, Object> sysJob) throws Exception;
}

 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值