package com.github.ltsopensource.jobtracker.complete; import com.github.ltsopensource.core.commons.utils.CollectionUtils; import com.github.ltsopensource.core.constant.Constants; import com.github.ltsopensource.core.constant.ExtConfig; import com.github.ltsopensource.core.domain.Job; import com.github.ltsopensource.core.domain.JobMeta; import com.github.ltsopensource.core.domain.JobRunResult; import com.github.ltsopensource.core.json.JSON; import com.github.ltsopensource.core.logger.Logger; import com.github.ltsopensource.core.logger.LoggerFactory; import com.github.ltsopensource.core.spi.ServiceLoader; 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.jobtracker.complete.retry.DefaultJobRetryTimeGenerator; import com.github.ltsopensource.jobtracker.complete.retry.JobRetryTimeGenerator; import com.github.ltsopensource.jobtracker.domain.JobTrackerAppContext; import com.github.ltsopensource.queue.domain.JobPo; import com.github.ltsopensource.store.jdbc.exception.DupEntryException; import java.util.Date; import java.util.List; /** * @author Robert HG (254963746@qq.com) on 11/11/15. */ public class JobRetryHandler { private static final Logger LOGGER = LoggerFactory.getLogger(JobRetryHandler.class); private JobTrackerAppContext appContext; private int retryInterval = 30 * 1000; // 默认30s private JobRetryTimeGenerator jobRetryTimeGenerator; public JobRetryHandler(JobTrackerAppContext appContext) { this.appContext = appContext; this.retryInterval = appContext.getConfig().getParameter(ExtConfig.JOB_TRACKER_JOB_RETRY_INTERVAL_MILLIS, 30 * 1000); this.jobRetryTimeGenerator = ServiceLoader.load(JobRetryTimeGenerator.class, appContext.getConfig()); } public void onComplete(List<JobRunResult> results) { if (CollectionUtils.isEmpty(results)) { return; } for (JobRunResult result : results) { JobMeta jobMeta = result.getJobMeta(); // 1. 加入到重试队列 JobPo jobPo = appContext.getExecutingJobQueue().getJob(jobMeta.getJobId()); if (jobPo == null) { // 表示已经被删除了 continue; } Job job = jobMeta.getJob(); if (!(jobRetryTimeGenerator instanceof DefaultJobRetryTimeGenerator)) { job = JobUtils.copy(jobMeta.getJob()); job.setTaskId(jobMeta.getRealTaskId()); // 这个对于用户需要转换为用户提交的taskId } // 得到下次重试时间 Long nextRetryTriggerTime = jobRetryTimeGenerator.getNextRetryTriggerTime(job, jobPo.getRetryTimes(), retryInterval); // 重试次数+1 jobPo.setRetryTimes((jobPo.getRetryTimes() == null ? 0 : jobPo.getRetryTimes()) + 1); if (jobPo.isCron()) { // 如果是 cron Job, 判断任务下一次执行时间和重试时间的比较 JobPo cronJobPo = appContext.getCronJobQueue().getJob(jobMeta.getJobId()); if (cronJobPo != null) { Date nextTriggerTime = CronExpressionUtils.getNextTriggerTime(cronJobPo.getCronExpression()); if (nextTriggerTime != null && nextTriggerTime.getTime() < nextRetryTriggerTime) { // 表示下次还要执行, 并且下次执行时间比下次重试时间要早, 那么不重试,直接使用下次的执行时间 nextRetryTriggerTime = nextTriggerTime.getTime(); jobPo = cronJobPo; } else { jobPo.setInternalExtParam(Constants.IS_RETRY_JOB, Boolean.TRUE.toString()); } } } else if (jobPo.isRepeatable()) { JobPo repeatJobPo = appContext.getRepeatJobQueue().getJob(jobMeta.getJobId()); if (repeatJobPo != null) { // 比较下一次重复时间和重试时间 if (repeatJobPo.getRepeatCount() == -1 || (repeatJobPo.getRepeatedCount() < repeatJobPo.getRepeatCount())) { long nexTriggerTime = JobUtils.getRepeatNextTriggerTime(jobPo); if (nexTriggerTime < nextRetryTriggerTime) { // 表示下次还要执行, 并且下次执行时间比下次重试时间要早, 那么不重试,直接使用下次的执行时间 nextRetryTriggerTime = nexTriggerTime; jobPo = repeatJobPo; } else { jobPo.setInternalExtParam(Constants.IS_RETRY_JOB, Boolean.TRUE.toString()); } } } } else { jobPo.setInternalExtParam(Constants.IS_RETRY_JOB, Boolean.TRUE.toString()); } // 加入到队列, 重试 jobPo.setTaskTrackerIdentity(null); jobPo.setIsRunning(false); jobPo.setGmtModified(SystemClock.now()); // 延迟重试时间就等于重试次数(分钟) jobPo.setTriggerTime(nextRetryTriggerTime); try { appContext.getExecutableJobQueue().add(jobPo); } catch (DupEntryException e) { LOGGER.warn("ExecutableJobQueue already exist:" + JSON.toJSONString(jobPo)); } // 从正在执行的队列中移除 appContext.getExecutingJobQueue().remove(jobPo.getJobId()); } } }