package com.github.ltsopensource.admin.web.api; import com.github.ltsopensource.admin.cluster.BackendAppContext; import com.github.ltsopensource.admin.request.JobQueueReq; import com.github.ltsopensource.admin.response.PaginationRsp; import com.github.ltsopensource.admin.web.AbstractMVC; import com.github.ltsopensource.admin.web.support.Builder; import com.github.ltsopensource.admin.web.vo.RestfulResponse; import com.github.ltsopensource.biz.logger.JobLogUtils; import com.github.ltsopensource.biz.logger.domain.LogType; import com.github.ltsopensource.core.commons.utils.Assert; import com.github.ltsopensource.core.commons.utils.StringUtils; import com.github.ltsopensource.core.constant.Constants; import com.github.ltsopensource.core.logger.Logger; import com.github.ltsopensource.core.logger.LoggerFactory; import com.github.ltsopensource.core.support.CronExpression; import com.github.ltsopensource.core.support.CronExpressionUtils; import com.github.ltsopensource.core.support.JobUtils; import com.github.ltsopensource.core.support.SystemClock; import com.github.ltsopensource.queue.domain.JobPo; import com.github.ltsopensource.store.jdbc.exception.DupEntryException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.text.ParseException; import java.util.Date; /** * @author Robert HG (254963746@qq.com) on 3/26/16. */ @RestController public class SuspendJobQueueApi extends AbstractMVC { private static final Logger LOGGER = LoggerFactory.getLogger(SuspendJobQueueApi.class); @Autowired private BackendAppContext appContext; @RequestMapping("/job-queue/suspend-job-get") public RestfulResponse suspendJobGet(JobQueueReq request) { PaginationRsp<JobPo> paginationRsp = appContext.getSuspendJobQueue().pageSelect(request); RestfulResponse response = new RestfulResponse(); response.setSuccess(true); response.setResults(paginationRsp.getResults()); response.setRows(paginationRsp.getRows()); return response; } @RequestMapping("/job-queue/suspend-job-update") public RestfulResponse suspendJobUpdate(String jobType, JobQueueReq request) { // 检查参数 try { Assert.hasLength(request.getJobId(), "jobId不能为空!"); Assert.hasLength(jobType, "jobType不能为空!"); } catch (IllegalArgumentException e) { return Builder.build(false, e.getMessage()); } try { JobPo jobPo = appContext.getSuspendJobQueue().getJob(request.getJobId()); if ("CRON".equals(jobType)) { // 检查参数 try { Assert.hasLength(request.getCronExpression(), "cronExpression不能为空!"); } catch (IllegalArgumentException e) { return Builder.build(false, e.getMessage()); } // 1. 检测 cronExpression是否是正确的 CronExpression expression = new CronExpression(request.getCronExpression()); if (expression.getTimeAfter(new Date()) == null) { return Builder.build(false, StringUtils.format("该CronExpression={} 已经没有执行时间点! 请重新设置或者直接删除。", request.getCronExpression())); } // 看CronExpression是否有修改,如果有修改,需要更新triggerTime if (!request.getCronExpression().equals(jobPo.getCronExpression())) { request.setTriggerTime(expression.getTimeAfter(new Date())); } } else { try { Assert.notNull(request.getRepeatInterval(), "repeatInterval不能为空!"); Assert.isTrue(request.getRepeatInterval() > 0, "repeatInterval必须大于0"); Assert.isTrue(request.getRepeatCount() >= -1, "repeatCount必须>= -1"); } catch (IllegalArgumentException e) { return Builder.build(false, e.getMessage()); } // 如果repeatInterval有修改,需要把triggerTime也要修改下 if (!request.getRepeatInterval().equals(jobPo.getRepeatInterval())) { long nextTriggerTime = JobUtils.getRepeatNextTriggerTime(jobPo); request.setTriggerTime(new Date(nextTriggerTime)); } request.setCronExpression(null); } boolean success = appContext.getSuspendJobQueue().selectiveUpdateByJobId(request); if (success) { JobLogUtils.log(LogType.UPDATE, jobPo, appContext.getJobLogger()); return Builder.build(true); } else { return Builder.build(false, "该任务已经被删除或者执行完成"); } } catch (ParseException e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "请输入正确的 CronExpression"); } } @RequestMapping("/job-queue/suspend-job-delete") public RestfulResponse suspendJobDelete(JobQueueReq request) { if (StringUtils.isEmpty(request.getJobId())) { return Builder.build(false, "JobId 必须传!"); } boolean success = appContext.getSuspendJobQueue().remove(request.getJobId()); if (success) { JobPo jobPo = appContext.getSuspendJobQueue().getJob(request.getJobId()); JobLogUtils.log(LogType.DEL, jobPo, appContext.getJobLogger()); } return Builder.build(success); } @RequestMapping("/job-queue/suspend-job-recovery") public RestfulResponse suspendJobRecovery(JobQueueReq request) { if (StringUtils.isEmpty(request.getJobId())) { return Builder.build(false, "JobId 必须传!"); } JobPo jobPo = appContext.getSuspendJobQueue().getJob(request.getJobId()); if (jobPo == null) { return Builder.build(false, "任务不存在,或者已经删除"); } // 判断是Cron任务还是Repeat任务 if (jobPo.isCron()) { // 先恢复,才能删除 Date nextTriggerTime = CronExpressionUtils.getNextTriggerTime(jobPo.getCronExpression()); if (nextTriggerTime != null) { jobPo.setGmtModified(SystemClock.now()); try { // 1.add to cron job queue appContext.getCronJobQueue().add(jobPo); } catch (DupEntryException e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "Cron队列中任务已经存在,请检查"); } catch (Exception e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "插入Cron队列中任务错误, error:" + e.getMessage()); } if (jobPo.getRelyOnPrevCycle()) { try { // 2. add to executable queue jobPo.setTriggerTime(nextTriggerTime.getTime()); jobPo.setInternalExtParam(Constants.EXE_SEQ_ID, JobUtils.generateExeSeqId(jobPo)); appContext.getExecutableJobQueue().add(jobPo); } catch (DupEntryException e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "等待执行队列中任务已经存在,请检查"); } catch (Exception e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "插入等待执行队列中任务错误, error:" + e.getMessage()); } } else { // 不依赖上一周期的 // Long lastGenerateTriggerTime = jobPo.getLastGenerateTriggerTime(); // if (lastGenerateTriggerTime == null || lastGenerateTriggerTime == 0) { // lastGenerateTriggerTime = SystemClock.now(); // } appContext.getNoRelyJobGenerator().generateCronJobForInterval(jobPo, new Date(SystemClock.now())); } } else { return Builder.build(false, "该任务已经无效, 或者已经没有下一轮执行时间点, 请直接删除"); } } else if (jobPo.isRepeatable()) { // 先恢复,才能删除 if (jobPo.getRepeatCount() == -1 || jobPo.getRepeatedCount() < jobPo.getRepeatCount()) { jobPo.setGmtModified(SystemClock.now()); try { // 1.add to cron job queue appContext.getRepeatJobQueue().add(jobPo); } catch (DupEntryException e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "Repeat队列中任务已经存在,请检查"); } catch (Exception e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "插入Repeat队列中任务错误, error:" + e.getMessage()); } if (jobPo.getRelyOnPrevCycle()) { try { // 2. add to executable queue JobPo repeatJob = appContext.getRepeatJobQueue().getJob(request.getJobId()); long nextTriggerTime = JobUtils.getRepeatNextTriggerTime(repeatJob); jobPo.setTriggerTime(nextTriggerTime); jobPo.setInternalExtParam(Constants.EXE_SEQ_ID, JobUtils.generateExeSeqId(jobPo)); appContext.getExecutableJobQueue().add(jobPo); } catch (DupEntryException e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "等待执行队列中任务已经存在,请检查"); } catch (Exception e) { LOGGER.error(e.getMessage(), e); return Builder.build(false, "插入等待执行队列中任务错误, error:" + e.getMessage()); } } else { // 不依赖上一周期的 // Long lastGenerateTriggerTime = jobPo.getLastGenerateTriggerTime(); // if (lastGenerateTriggerTime == null || lastGenerateTriggerTime == 0) { // lastGenerateTriggerTime = SystemClock.now(); // } appContext.getNoRelyJobGenerator().generateRepeatJobForInterval(jobPo, new Date(SystemClock.now())); } } else { return Builder.build(false, "该任务已经无效, 或者已经没有下一轮执行时间点, 请直接删除"); } } // 从暂停表中移除 if (!appContext.getSuspendJobQueue().remove(request.getJobId())) { return Builder.build(false, "恢复暂停任务失败,请重试"); } JobLogUtils.log(LogType.RESUME, jobPo, appContext.getJobLogger()); return Builder.build(true); } }