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.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 CronJobQueueApi extends AbstractMVC {
private static final Logger LOGGER = LoggerFactory.getLogger(CronJobQueueApi.class);
@Autowired
private BackendAppContext appContext;
@RequestMapping("/job-queue/cron-job-get")
public RestfulResponse cronJobGet(JobQueueReq request) {
PaginationRsp<JobPo> paginationRsp = appContext.getCronJobQueue().pageSelect(request);
RestfulResponse response = new RestfulResponse();
response.setSuccess(true);
response.setResults(paginationRsp.getResults());
response.setRows(paginationRsp.getRows());
return response;
}
@RequestMapping("/job-queue/cron-job-update")
public RestfulResponse cronJobUpdate(JobQueueReq request) {
RestfulResponse response = new RestfulResponse();
// 检查参数
try {
Assert.hasLength(request.getJobId(), "jobId不能为空!");
Assert.hasLength(request.getCronExpression(), "cronExpression不能为空!");
} catch (IllegalArgumentException e) {
return Builder.build(false, e.getMessage());
}
try {
// 1. 检测 cronExpression是否是正确的
CronExpression expression = new CronExpression(request.getCronExpression());
Date nextTriggerTime = expression.getTimeAfter(new Date());
if (nextTriggerTime == null) {
return Builder.build(false, StringUtils.format("该CronExpression={} 已经没有执行时间点! 请重新设置或者直接删除。", request.getCronExpression()));
}
JobPo oldJobPo = appContext.getCronJobQueue().getJob(request.getJobId());
boolean success = appContext.getCronJobQueue().selectiveUpdateByJobId(request);
if (success) {
JobPo newJobPo = appContext.getCronJobQueue().getJob(request.getJobId());
try {
// 判断是否有relyOnPrevCycle变更
boolean relyOnPrevCycleChanged = !newJobPo.getRelyOnPrevCycle().equals(oldJobPo.getRelyOnPrevCycle());
boolean cronExpressionChanged = !newJobPo.getCronExpression().equals(oldJobPo.getCronExpression());
// 1. 修改前relyOnPrevCycle=true,并且修改后也是true
if (oldJobPo.getRelyOnPrevCycle() && !relyOnPrevCycleChanged) {
// 看CronExpression是否有修改,如果有修改,需要更新triggerTime
if (cronExpressionChanged) {
request.setTriggerTime(nextTriggerTime);
}
appContext.getExecutableJobQueue().selectiveUpdateByJobId(request);
} else {
// 2. 需要对批量任务做处理
if (relyOnPrevCycleChanged) {
// 如果relyOnPrevCycle 修改过
if (oldJobPo.getRelyOnPrevCycle()) {
// 之前是依赖的,现在不依赖,需要生成批量任务
appContext.getExecutableJobQueue().remove(oldJobPo.getTaskTrackerNodeGroup(), oldJobPo.getJobId());
appContext.getNoRelyJobGenerator().generateCronJobForInterval(newJobPo, new Date());
} else {
// 之前不依赖,现在依赖,需要删除批量任务
appContext.getExecutableJobQueue().removeBatch(oldJobPo.getRealTaskId(), oldJobPo.getTaskTrackerNodeGroup());
// 添加新的任务
newJobPo.setTriggerTime(nextTriggerTime.getTime());
try {
newJobPo.setInternalExtParam(Constants.EXE_SEQ_ID, JobUtils.generateExeSeqId(newJobPo));
appContext.getExecutableJobQueue().add(newJobPo);
} catch (DupEntryException ignored) {
}
}
} else {
// 如果relyOnPrevCycle 没有修改过, 表示relyOnPrevCycle=false, 那么要看cronExpression是否修改过,如果修改过,需要删除重新生成
if (cronExpressionChanged) {
appContext.getExecutableJobQueue().removeBatch(oldJobPo.getRealTaskId(), oldJobPo.getTaskTrackerNodeGroup());
appContext.getNoRelyJobGenerator().generateCronJobForInterval(newJobPo, new Date());
} else {
appContext.getExecutableJobQueue().selectiveUpdateByTaskId(request);
}
}
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return Builder.build(false, "更新等待执行的任务失败,请手动更新! error:" + e.getMessage());
}
response.setSuccess(true);
} else {
return Builder.build(false, "该任务已经被删除或者执行完成");
}
JobLogUtils.log(LogType.UPDATE, oldJobPo, appContext.getJobLogger());
return response;
} catch (ParseException e) {
LOGGER.error(e.getMessage(), e);
return Builder.build(false, "请输入正确的 CronExpression!" + e.getMessage());
}
}
@RequestMapping("/job-queue/cron-job-delete")
public RestfulResponse cronJobDelete(JobQueueReq request) {
if (StringUtils.isEmpty(request.getJobId())) {
return Builder.build(false, "JobId 必须传!");
}
JobPo jobPo = appContext.getCronJobQueue().getJob(request.getJobId());
if (jobPo == null) {
return Builder.build(true, "已经删除");
}
boolean success = appContext.getCronJobQueue().remove(request.getJobId());
if (success) {
try {
appContext.getExecutableJobQueue().removeBatch(jobPo.getRealTaskId(), jobPo.getTaskTrackerNodeGroup());
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return Builder.build(false, "删除等待执行的任务失败,请手动删除! error:{}" + e.getMessage());
}
}
JobLogUtils.log(LogType.DEL, jobPo, appContext.getJobLogger());
return Builder.build(true, "ok");
}
@RequestMapping("/job-queue/cron-job-suspend")
public RestfulResponse cronJobSuspend(JobQueueReq request) {
if (StringUtils.isEmpty(request.getJobId())) {
return Builder.build(false, "JobId 必须传!");
}
JobPo jobPo = appContext.getCronJobQueue().getJob(request.getJobId());
if (jobPo == null) {
return Builder.build(false, "任务不存在,或者已经删除");
}
try {
jobPo.setGmtModified(SystemClock.now());
appContext.getSuspendJobQueue().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());
}
try {
appContext.getCronJobQueue().remove(request.getJobId());
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return Builder.build(false, "删除Cron任务失败,请手动删除! error:" + e.getMessage());
}
try {
if (!jobPo.getRelyOnPrevCycle()) {
appContext.getCronJobQueue().updateLastGenerateTriggerTime(jobPo.getJobId(), new Date().getTime());
appContext.getExecutableJobQueue().removeBatch(jobPo.getRealTaskId(), jobPo.getTaskTrackerNodeGroup());
} else {
appContext.getExecutableJobQueue().remove(request.getTaskTrackerNodeGroup(), request.getJobId());
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return Builder.build(false, "删除等待执行的任务失败,请手动删除! error:" + e.getMessage());
}
// 记录日志
JobLogUtils.log(LogType.SUSPEND, jobPo, appContext.getJobLogger());
return Builder.build(true, "ok");
}
}