作业调度框架 Quartz

调度器核心代码:

import nd.sdp.lcreporting.schedule.model.Schedule;
import nd.sdp.lcreporting.schedule.service.ScheduleService;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class QuartzJobScheduler {

    private static final String CRON_GROUP = "CRON_QUARTZ_GROUP";
    private static final String TRIGGER_ONCE_QUARTZ_GROUP = "TRIGGER_ONCE_QUARTZ_GROUP";
    private static final Logger LOGGER = LoggerFactory.getLogger(QuartzJobScheduler.class);
    @Resource
    private Scheduler scheduler;
    @Resource
    private ScheduleService scheduleService;


    /**
     * 通过schedule生成一个quartz调度任务<br/>
     * <p>
     *     会先删除name为schedule.getName()对应的任务和触发器,重新调度
     * </p>
     * @param schedule Schedule
     * @throws SchedulerException Scheduler exception
     */
    public void scheduleJob(Schedule schedule) throws SchedulerException {
        String name = schedule.getName();
        deleteJob(name);
        TriggerKey triggerKey = TriggerKey.triggerKey(name, CRON_GROUP);
        JobKey jobKey = JobKey.jobKey(name, CRON_GROUP);
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(
                        CronScheduleBuilder.cronSchedule(schedule.getCron())
                                .withMisfireHandlingInstructionIgnoreMisfires())
                .build();
        JobDetail jobDetail = JobBuilder.newJob(QuartzJobExecutor.class)
                .withIdentity(jobKey)
                .build();
        jobDetail.getJobDataMap().put(Schedule.SCHEDULE, schedule);
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 删除 name为name,group为CRON_GROUP对应的任务和触发器
     * @param name job name
     * @throws SchedulerException scheduler exception
     */
    public void deleteJob(String name) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name, CRON_GROUP);
        boolean success = scheduler.deleteJob(jobKey);
        if (!success) {
            LOGGER.info("job {}-{} not found and deleted.", jobKey.getName(), jobKey.getGroup());
        }
    }

    public void triggerJobNow(Schedule schedule) throws SchedulerException {
        schedule.setTriggerOnce(true);
        JobDetail jobDetail;
        //jobKey name 加上时间窗口后缀,避免拆分后key冲突
        Object startTime = schedule.getExtendedProperties().get(ScheduleConstants.TIME_SECTION_START_TIME_KEY);
        Object endTime = schedule.getExtendedProperties().get(ScheduleConstants.TIME_SECTION_END_TIME_KEY);
        String name = String.format("%s_%s_%s",schedule.getName(), startTime, endTime);
        //使用group:TRIGGER_ONCE_QUARTZ_GROUP,与cron任务区分开来
        JobKey jobKey = JobKey.jobKey(name, TRIGGER_ONCE_QUARTZ_GROUP);
        jobDetail = JobBuilder.newJob(QuartzJobExecutor.class).withIdentity(jobKey)
                .storeDurably(true).build();
        jobDetail.getJobDataMap().put(Schedule.SCHEDULE, schedule);
        try {
            this.scheduler.addJob(jobDetail, true);
        } catch (SchedulerException e) {
            LOGGER.error("triggerJobNow add job fail", e);
            throw e;
        }
        try {
            this.scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            LOGGER.error("triggerJobNow trigger job fail", e);
            throw e;
        }
    }

    public int getCurrentlyExecutingJobsCount() throws SchedulerException {
        return scheduler.getCurrentlyExecutingJobs().size();
    }

}

Controller层:

@RestController
@RequestMapping(value = "/v0.1/schedules")
public class ScheduleController {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleController.class);

    @Resource
    private QuartzJobScheduler quartzJobScheduler;
    @Resource
    private ScheduleService scheduleService;

    @RequestMapping(value = "", method = RequestMethod.POST)
    public Object createSchedule(@RequestBody Schedule schedule) {
        String message = "调度任务创建成功";
        schedule = scheduleService.create(schedule);
        try {
            quartzJobScheduler.scheduleJob(schedule);
        } catch (SchedulerException e) {
            message = e.getMessage();
            LOGGER.error("schedule job error, will delete schedule", e);
            scheduleService.delete(schedule.getName());
        }
        Map<String, String> result = new HashMap<>();
        result.put("message", message);
        return result;
    }

    @RequestMapping(value = "", method = RequestMethod.PUT)
    public Object reschedule(@RequestBody Schedule schedule) {
        String message = "重新调度任务成功";
        schedule = scheduleService.update(schedule);
        try {
            quartzJobScheduler.scheduleJob(schedule);
        } catch (SchedulerException e) {
            message = e.getMessage();
            LOGGER.error("reschedule job error", e);
        }
        Map<String, String> result = new HashMap<>();
        result.put("message", message);
        return result;
    }

    @RequestMapping(value = "{name}", method = RequestMethod.DELETE)
    public Object deleteSchedule(@PathVariable String name) {
        String message = "调度任务删除成功";
        scheduleService.delete(name);
        try {
            quartzJobScheduler.deleteJob(name);
        } catch (SchedulerException e) {
            message = e.getMessage();
            LOGGER.error("delete schedule job error", e);
        }
        Map<String, String> result = new HashMap<>();
        result.put("message", message);
        return result;
    }

    @RequestMapping(value = "trigger_once", method = RequestMethod.POST)
    public Object triggerOnce(@RequestBody TriggerOnceSchedule triggerOnceSchedule) {
        String message = "单次触发调度任务成功";
        String scheduleName = triggerOnceSchedule.getScheduleName();
        if (StringUtils.isEmpty(scheduleName)) {
            throw new BizException(ErrorCode.INVALID_ARGUMENT, "schedule_name不能为空");
        }
        long startTime = triggerOnceSchedule.getTimeSectionStartTime();
        long endTime = triggerOnceSchedule.getTimeSectionEndTime();
        if (startTime == 0 || endTime == 0 || startTime > endTime) {
            throw new BizException(ErrorCode.INVALID_ARGUMENT, "时间窗参数不正确");
        }
        List<Schedule.ScheduleJob> jobs;
        //从数据库中获取Job配置
        if (triggerOnceSchedule.isFetchJobsByScheduleName()) {
            Schedule scheduleFromDB = scheduleService.find(triggerOnceSchedule.getScheduleName());
            if (scheduleFromDB == null) {
                throw new BizException(ErrorCode.DATA_NOT_EXIST, "找不到对应的schedule");
            }
            jobs = scheduleFromDB.getJobs();
        } else {
            jobs = triggerOnceSchedule.getJobs();
        }
        List<Schedule> splitScheduleList = splitSchedule(triggerOnceSchedule, jobs);
        for (Schedule schedule : splitScheduleList) {
            try {
                quartzJobScheduler.triggerJobNow(schedule);
            } catch (SchedulerException e) {
                message = e.getMessage();
                LOGGER.error("trigger job error", e);
                break;
            }
        }
        Map<String, Object> result = new HashMap<>();
        result.put("message", message);
        result.put("schedules", splitScheduleList);
        return result;
    }

    private static final long MAX_TIME_SECTION_SIZE = 2592000000L;//30天
    private List<Schedule> splitSchedule(TriggerOnceSchedule triggerOnceSchedule, List<Schedule.ScheduleJob> jobs) {
        List<Schedule> scheduleList;
        long startTime = triggerOnceSchedule.getTimeSectionStartTime();
        long endTime = triggerOnceSchedule.getTimeSectionEndTime();
        if (triggerOnceSchedule.getSplitSize() > 1) {//按指定大小拆分
            long deltaSize = (long) Math.ceil(1.0*(endTime-startTime)/triggerOnceSchedule.getSplitSize());
            scheduleList = splitWithDeltaSize(triggerOnceSchedule, jobs, deltaSize);
        } else if (endTime - startTime > MAX_TIME_SECTION_SIZE) { //如果时间窗口大于30天,自动拆分成最大30天的窗口大小
            scheduleList = splitWithDeltaSize(triggerOnceSchedule, jobs, MAX_TIME_SECTION_SIZE);
        } else { //不拆分
            scheduleList = new ArrayList<>(1);
            Schedule schedule = buildSchedule(triggerOnceSchedule.getScheduleName(), triggerOnceSchedule.getScheduleDesc(),
                    jobs, startTime, endTime);
            scheduleList.add(schedule);
        }
        return scheduleList;
    }

    private List<Schedule> splitWithDeltaSize(TriggerOnceSchedule triggerOnceSchedule, List<Schedule.ScheduleJob> jobs, long deltaSize) {
        List<Schedule> scheduleList = new ArrayList<>();
        long startTime = triggerOnceSchedule.getTimeSectionStartTime();
        long endTime = triggerOnceSchedule.getTimeSectionEndTime();
        long splitStartTime = startTime;
        long splitEndTime = startTime + deltaSize;
        while (splitEndTime <= endTime) {
            Schedule schedule = buildSchedule(triggerOnceSchedule.getScheduleName(), triggerOnceSchedule.getScheduleDesc(),
                    jobs, splitStartTime, splitEndTime);
            scheduleList.add(schedule);
            splitStartTime = splitEndTime;
            splitEndTime += deltaSize;
        }
        //把最后一段拼上
        if (splitStartTime < endTime) {
            Schedule schedule = buildSchedule(triggerOnceSchedule.getScheduleName(), triggerOnceSchedule.getScheduleDesc(),
                    jobs, splitStartTime, endTime);
            scheduleList.add(schedule);
        }
        return scheduleList;
    }

    private Schedule buildSchedule(String name, String desc, List<Schedule.ScheduleJob> jobs, long startTime, long endTime) {
        Schedule schedule = new Schedule();
        schedule.setJobs(jobs);
        schedule.setName(name);
        schedule.setDesc(desc);
        schedule.getExtendedProperties().put(ScheduleConstants.TIME_SECTION_START_TIME_KEY, startTime);
        schedule.getExtendedProperties().put(ScheduleConstants.TIME_SECTION_END_TIME_KEY, endTime);
        return schedule;
    }

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值