View Javadoc
1   /*
2    * Copyright (C) 2024 B3Partners B.V.
3    *
4    * SPDX-License-Identifier: MIT
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.UUID;
12  import org.quartz.CronScheduleBuilder;
13  import org.quartz.DateBuilder;
14  import org.quartz.JobBuilder;
15  import org.quartz.JobDataMap;
16  import org.quartz.JobDetail;
17  import org.quartz.JobKey;
18  import org.quartz.ObjectAlreadyExistsException;
19  import org.quartz.Scheduler;
20  import org.quartz.SchedulerException;
21  import org.quartz.Trigger;
22  import org.quartz.TriggerBuilder;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.springframework.beans.factory.annotation.Autowired;
26  import org.springframework.scheduling.quartz.QuartzJobBean;
27  import org.springframework.stereotype.Service;
28  
29  @Service
30  public class TaskCreator {
31    private static final Logger logger =
32        LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
33  
34    private final Scheduler scheduler;
35  
36    public TaskCreator(@Autowired Scheduler scheduler) {
37      this.scheduler = scheduler;
38    }
39  
40    /**
41     * Create a job and schedule it with a cron expression.
42     *
43     * @param job the task class to create
44     * @param jobData a map with job data, the {@code type} and {@code description} keys are mandatory
45     * @param cronExpression the cron expression
46     * @return the task name, a UUID
47     * @throws SchedulerException if the job could not be scheduled
48     */
49    public String createTask(
50        Class<? extends QuartzJobBean> job, TMJobDataMap jobData, String cronExpression)
51        throws SchedulerException {
52  
53      // Create a job
54      JobDetail jobDetail =
55          JobBuilder.newJob(job)
56              .withIdentity(new JobKey(UUID.randomUUID().toString(), jobData.get("type").toString()))
57              .withDescription(jobData.getDescription())
58              .usingJobData(new JobDataMap(jobData))
59              .build();
60  
61      // Create a trigger
62      Trigger trigger =
63          TriggerBuilder.newTrigger()
64              .withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
65              .startAt(DateBuilder.futureDate(30, DateBuilder.IntervalUnit.SECOND))
66              .withPriority(jobData.getPriority())
67              .usingJobData(SENTRY_SLUG_KEY, "monitor_slug_cron_trigger_" + jobData.get("type"))
68              .withSchedule(
69                  CronScheduleBuilder.cronSchedule(cronExpression)
70                      .withMisfireHandlingInstructionFireAndProceed())
71              .build();
72  
73      try {
74        scheduler.scheduleJob(jobDetail, trigger);
75      } catch (ObjectAlreadyExistsException ex) {
76        logger.warn(
77            "Job {} with trigger {} has not bean added to scheduler as it already exists.",
78            jobDetail.getKey(),
79            trigger.getKey());
80        return null;
81      }
82  
83      return jobDetail.getKey().getName();
84    }
85  }