
ru.taskurotta.service.schedule.QuartzJobManager Maven / Gradle / Ivy
package ru.taskurotta.service.schedule;
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.taskurotta.server.TaskServer;
import ru.taskurotta.service.console.retriever.QueueInfoRetriever;
import ru.taskurotta.service.schedule.model.JobVO;
import ru.taskurotta.service.schedule.storage.JobStore;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* Default implementation of scheduled task manager with Quartz
* User: dimadin
* Date: 24.09.13 10:17
*/
public class QuartzJobManager implements JobManager {
private static final Logger logger = LoggerFactory.getLogger(QuartzJobManager.class);
private JobStore jobStore;
private Scheduler scheduler;
private QueueInfoRetriever queueInfoRetriever;
private TaskServer taskServer;
public QuartzJobManager(TaskServer taskServer, JobStore jobStore, QueueInfoRetriever queueInfoRetriever) throws SchedulerException {
this.jobStore = jobStore;
this.taskServer = taskServer;
this.queueInfoRetriever = queueInfoRetriever;
this.scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
}
@Override
public boolean startJob(long id) {
boolean result = false;
JobVO job = jobStore.getJob(id);
if (job != null) {
try {
if (!isActive(job)) {
runJob(job);
jobStore.updateJobStatus(job.getId(), JobConstants.STATUS_ACTIVE);
}
result = true;
} catch (Throwable e) {
logger.error("Error starting scheduler for id["+id+"]", e);
stopJob(id);
jobStore.updateJobStatus(id, JobConstants.STATUS_ERROR);
}
}
logger.debug("Job id[{}] start result is[{}]. JobVO is[{}]", id, result, job);
return result;
}
public boolean isActive(JobVO job) {
if (job == null) {
throw new IllegalArgumentException("Cannot check state for null job");
}
boolean result = false;
try {
JobDetail jd = scheduler.getJobDetail(JobKey.jobKey(String.valueOf(job.getId()), job.getName()));
result = jd!=null;
} catch (SchedulerException e) {
logger.error("Error determine running state for ["+job+"]", e);
}
logger.debug("Job name [{}] isScheduled[{}], job[{}]", job.getName(), result, job);
return result;
}
public Collection getScheduledJobIds() {
Collection result = null;
try {
List jobGroupNames = scheduler.getJobGroupNames();
if (jobGroupNames!=null && !jobGroupNames.isEmpty()) {
result = new ArrayList<>();
for (String groupName : jobGroupNames) {
Set jobKeyList = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
if (jobKeyList!=null && !jobKeyList.isEmpty()) {
for (JobKey jobKey : jobKeyList) {
Long longValue = null;
String jobIdStr = jobKey.getName();
try {
longValue = Long.parseLong(jobIdStr);
} catch (Exception e) {
logger.error("Cannot parse job id ["+jobIdStr+"]", e);
longValue = -1l;
}
result.add(longValue);
}
}
}
}
} catch(SchedulerException e) {
String errorMessage = "Error at getting job ids: " + e.getMessage();
logger.error(errorMessage, e);
throw new RuntimeException(errorMessage);
}
return result;
}
@Override
public long addJob(JobVO job) {
return jobStore.addJob(job);
}
@Override
public void removeJob(long id) {
stopJob(id);
jobStore.removeJob(id);
}
@Override
public Collection getJobIds() {
return jobStore.getJobIds();
}
@Override
public JobVO getJob(long id) {
return jobStore.getJob(id);
}
@Override
public void updateJobStatus(long id, int status) {
jobStore.updateJobStatus(id, status);
}
@Override
public void updateJob(JobVO jobVO) {
stopJob(jobVO.getId());
jobStore.updateJob(jobVO);
}
@Override
public void updateErrorCount(long jobId, int count, String message) {
jobStore.updateErrorCount(jobId, count, message);
}
private void runJob(JobVO job) throws SchedulerException {
JobDataMap jdm = new JobDataMap();
jdm.put(JobConstants.DATA_KEY_JOB, job);
jdm.put(JobConstants.DATA_KEY_QUEUE_INFO_RETRIEVER, queueInfoRetriever);
jdm.put(JobConstants.DATA_KEY_TASK_SERVER, taskServer);
jdm.put(JobConstants.DATA_KEY_JOB_MANAGER, this);
JobDetail jobDetail = JobBuilder
.newJob(EnqueueTaskJob.class)
.withIdentity(String.valueOf(job.getId()), job.getName())
.usingJobData(jdm)
.build();
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(String.valueOf(job.getId()), job.getName())
.withSchedule(
CronScheduleBuilder.cronSchedule(job.getCron()))
.build();
scheduler.scheduleJob(jobDetail, trigger);
logger.debug("New job has been scheduled, [{}]", job);
}
private void stopJob(JobVO task) throws SchedulerException {
boolean result = scheduler.deleteJob(JobKey.jobKey(String.valueOf(task.getId()),task.getName()));
jobStore.updateJobStatus(task.getId(), JobConstants.STATUS_INACTIVE);
logger.debug("Job delete result is[{}], job[{}]", result, task);
if (!result) {
logger.warn("Job was not found for deletion, [{}]", task);
}
}
@Override
public boolean stopJob(long id) {
boolean result = false;
JobVO job = jobStore.getJob(id);
if (job != null) {
try {
if(isActive(job)) {
stopJob(job);
jobStore.updateJobStatus(job.getId(), JobConstants.STATUS_INACTIVE);
}
result = true;
} catch (Throwable e) {
logger.error("Error stopping scheduler for id["+id+"]", e);
}
logger.debug("Job [{}] stop result is[{}]. JobVO is[{}]", job.getName(), result, job);
}
return result;
}
@Override
public int getJobStatus(long id) {
int result = JobConstants.STATUS_UNDEFINED;
JobVO job = jobStore.getJob(id);
if (job!=null) {
result = job.getStatus();
}
return result;
}
@Override
public Date getNextExecutionTime(long id) {
Date result = null;
try {
JobVO job = jobStore.getJob(id);
if (job != null) {
CronExpression expr = new CronExpression(job.getCron());
result = expr.getNextValidTimeAfter(new Date());
}
} catch (ParseException e) {
logger.error("Error parsing cron expression[{}] for job id [{}]", id);
}
return result;
}
@Override
public void synchronizeScheduledTasksWithStore() {
Collection jobIds = jobStore.getJobIds();
List resumedJobs = new ArrayList();
if (jobIds!=null && !jobIds.isEmpty()) {
for (Long jobId : jobIds) {
JobVO sTask = jobStore.getJob(jobId);
if (sTask!=null && JobConstants.STATUS_ACTIVE == sTask.getStatus()) {
startJob(jobId);
resumedJobs.add(jobId);
}
}
}
logger.info("Resumed jobs on schedule after sync are [{}]", resumedJobs);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy