1
2
3
4
5
6 package org.tailormap.api.scheduling;
7
8 import static io.sentry.quartz.SentryJobListener.SENTRY_SLUG_KEY;
9
10 import java.lang.invoke.MethodHandles;
11 import java.util.Set;
12 import java.util.UUID;
13 import org.quartz.CronScheduleBuilder;
14 import org.quartz.DateBuilder;
15 import org.quartz.JobBuilder;
16 import org.quartz.JobDataMap;
17 import org.quartz.JobDetail;
18 import org.quartz.JobKey;
19 import org.quartz.ObjectAlreadyExistsException;
20 import org.quartz.Scheduler;
21 import org.quartz.SchedulerException;
22 import org.quartz.Trigger;
23 import org.quartz.TriggerBuilder;
24 import org.quartz.impl.matchers.GroupMatcher;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27 import org.springframework.beans.factory.annotation.Autowired;
28 import org.springframework.lang.Nullable;
29 import org.springframework.scheduling.quartz.QuartzJobBean;
30 import org.springframework.stereotype.Service;
31
32 @Service
33 public class TaskManagerService {
34 private static final Logger logger =
35 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
36
37 private final Scheduler scheduler;
38
39 public TaskManagerService(@Autowired Scheduler scheduler) {
40 this.scheduler = scheduler;
41 }
42
43
44
45
46
47
48
49
50
51 public UUID createTask(Class<? extends QuartzJobBean> job, TMJobDataMap jobData) throws SchedulerException {
52 JobDetail jobDetail = JobBuilder.newJob(job)
53 .withIdentity(new JobKey(
54 UUID.randomUUID().toString(), jobData.get(Task.TYPE_KEY).toString()))
55 .withDescription(jobData.getDescription())
56 .usingJobData(new JobDataMap(jobData))
57 .storeDurably(false)
58 .build();
59
60 Trigger trigger = TriggerBuilder.newTrigger()
61 .withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
62 .startNow()
63 .withPriority(jobData.getPriority())
64 .usingJobData(SENTRY_SLUG_KEY, "monitor_slug_simple_trigger_" + jobData.get(Task.TYPE_KEY))
65 .forJob(jobDetail)
66 .build();
67
68 scheduler.scheduleJob(jobDetail, Set.of(trigger), true);
69 return UUID.fromString(jobDetail.getKey().getName());
70 }
71
72
73
74
75
76
77
78
79
80
81 public UUID createTask(Class<? extends QuartzJobBean> job, TMJobDataMap jobData, String cronExpression)
82 throws SchedulerException {
83
84
85 JobDetail jobDetail = JobBuilder.newJob(job)
86 .withIdentity(new JobKey(
87 UUID.randomUUID().toString(), jobData.get(Task.TYPE_KEY).toString()))
88 .withDescription(jobData.getDescription())
89 .usingJobData(new JobDataMap(jobData))
90 .build();
91
92
93 Trigger trigger = TriggerBuilder.newTrigger()
94 .withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
95 .startAt(DateBuilder.futureDate(90, DateBuilder.IntervalUnit.SECOND))
96 .withPriority(jobData.getPriority())
97 .usingJobData(SENTRY_SLUG_KEY, "monitor_slug_cron_trigger_" + jobData.get(Task.TYPE_KEY))
98 .withSchedule(
99 CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionFireAndProceed())
100 .build();
101
102 try {
103 scheduler.scheduleJob(jobDetail, trigger);
104 } catch (ObjectAlreadyExistsException ex) {
105 logger.warn(
106 "Job {} with trigger {} has not bean added to scheduler as it already exists.",
107 jobDetail.getKey(),
108 trigger.getKey());
109 return null;
110 }
111
112 return UUID.fromString(jobDetail.getKey().getName());
113 }
114
115
116
117
118
119
120
121
122 public void updateTask(JobKey jobKey, TMJobDataMap newJobData) throws SchedulerException {
123
124 if (scheduler.checkExists(jobKey)) {
125
126 Trigger oldTrigger = scheduler.getTriggersOfJob(jobKey).get(0);
127
128 if (scheduler.checkExists(oldTrigger.getKey())) {
129
130 JobDetail jobDetail = scheduler.getJobDetail(jobKey);
131 JobDataMap jobDataMap = jobDetail.getJobDataMap();
132 jobDataMap.putAll(newJobData);
133
134 Trigger newTrigger = TriggerBuilder.newTrigger()
135 .withIdentity(jobKey.getName(), jobKey.getGroup())
136 .startAt(DateBuilder.futureDate(90, DateBuilder.IntervalUnit.SECOND))
137 .withPriority(jobDataMap.getInt(Task.PRIORITY_KEY))
138 .usingJobData(
139 SENTRY_SLUG_KEY,
140 "monitor_slug_cron_trigger_"
141 + jobDataMap.get(Task.TYPE_KEY).toString())
142 .withSchedule(CronScheduleBuilder.cronSchedule(jobDataMap.getString(Task.CRON_EXPRESSION_KEY))
143 .withMisfireHandlingInstructionFireAndProceed())
144 .build();
145
146 scheduler.addJob(jobDetail, true, true);
147 scheduler.rescheduleJob(oldTrigger.getKey(), newTrigger);
148 }
149 }
150 }
151
152
153
154
155
156
157
158
159
160 @Nullable public JobKey getJobKey(TaskType jobType, UUID uuid) throws SchedulerException {
161 logger.debug("Finding job key for task {}:{}", jobType, uuid);
162 return scheduler.getJobKeys(GroupMatcher.groupEquals(jobType.getValue())).stream()
163 .filter(jobkey -> jobkey.getName().equals(uuid.toString()))
164 .findFirst()
165 .orElse(null);
166 }
167 }