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)
52 throws SchedulerException {
53 JobDetail jobDetail =
54 JobBuilder.newJob(job)
55 .withIdentity(
56 new JobKey(UUID.randomUUID().toString(), jobData.get(Task.TYPE_KEY).toString()))
57 .withDescription(jobData.getDescription())
58 .usingJobData(new JobDataMap(jobData))
59 .storeDurably(false)
60 .build();
61
62 Trigger trigger =
63 TriggerBuilder.newTrigger()
64 .withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
65 .startNow()
66 .withPriority(jobData.getPriority())
67 .usingJobData(
68 SENTRY_SLUG_KEY, "monitor_slug_simple_trigger_" + jobData.get(Task.TYPE_KEY))
69 .forJob(jobDetail)
70 .build();
71
72 scheduler.scheduleJob(jobDetail, Set.of(trigger), true);
73 return UUID.fromString(jobDetail.getKey().getName());
74 }
75
76
77
78
79
80
81
82
83
84
85 public UUID createTask(
86 Class<? extends QuartzJobBean> job, TMJobDataMap jobData, String cronExpression)
87 throws SchedulerException {
88
89
90 JobDetail jobDetail =
91 JobBuilder.newJob(job)
92 .withIdentity(
93 new JobKey(UUID.randomUUID().toString(), jobData.get(Task.TYPE_KEY).toString()))
94 .withDescription(jobData.getDescription())
95 .usingJobData(new JobDataMap(jobData))
96 .build();
97
98
99 Trigger trigger =
100 TriggerBuilder.newTrigger()
101 .withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
102 .startAt(DateBuilder.futureDate(90, DateBuilder.IntervalUnit.SECOND))
103 .withPriority(jobData.getPriority())
104 .usingJobData(
105 SENTRY_SLUG_KEY, "monitor_slug_cron_trigger_" + jobData.get(Task.TYPE_KEY))
106 .withSchedule(
107 CronScheduleBuilder.cronSchedule(cronExpression)
108 .withMisfireHandlingInstructionFireAndProceed())
109 .build();
110
111 try {
112 scheduler.scheduleJob(jobDetail, trigger);
113 } catch (ObjectAlreadyExistsException ex) {
114 logger.warn(
115 "Job {} with trigger {} has not bean added to scheduler as it already exists.",
116 jobDetail.getKey(),
117 trigger.getKey());
118 return null;
119 }
120
121 return UUID.fromString(jobDetail.getKey().getName());
122 }
123
124
125
126
127
128
129
130
131 public void updateTask(JobKey jobKey, TMJobDataMap newJobData) throws SchedulerException {
132
133 if (scheduler.checkExists(jobKey)) {
134
135 Trigger oldTrigger = scheduler.getTriggersOfJob(jobKey).get(0);
136
137 if (scheduler.checkExists(oldTrigger.getKey())) {
138
139 JobDetail jobDetail = scheduler.getJobDetail(jobKey);
140 JobDataMap jobDataMap = jobDetail.getJobDataMap();
141 jobDataMap.putAll(newJobData);
142
143 Trigger newTrigger =
144 TriggerBuilder.newTrigger()
145 .withIdentity(jobKey.getName(), jobKey.getGroup())
146 .startAt(DateBuilder.futureDate(90, DateBuilder.IntervalUnit.SECOND))
147 .withPriority(jobDataMap.getInt(Task.PRIORITY_KEY))
148 .usingJobData(
149 SENTRY_SLUG_KEY,
150 "monitor_slug_cron_trigger_" + jobDataMap.get(Task.TYPE_KEY).toString())
151 .withSchedule(
152 CronScheduleBuilder.cronSchedule(jobDataMap.getString(Task.CRON_EXPRESSION_KEY))
153 .withMisfireHandlingInstructionFireAndProceed())
154 .build();
155
156 scheduler.addJob(jobDetail, true, true);
157 scheduler.rescheduleJob(oldTrigger.getKey(), newTrigger);
158 }
159 }
160 }
161
162
163
164
165
166
167
168
169
170 @Nullable
171 public JobKey getJobKey(TaskType jobType, UUID uuid) throws SchedulerException {
172 logger.debug("Finding job key for task {}:{}", jobType, uuid);
173 return scheduler.getJobKeys(GroupMatcher.groupEquals(jobType.getValue())).stream()
174 .filter(jobkey -> jobkey.getName().equals(uuid.toString()))
175 .findFirst()
176 .orElse(null);
177 }
178 }