mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-03-11 01:36:33 +00:00
added java doc and some comments to scheduling module
This commit is contained in:
@@ -8,6 +8,9 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Makes the job configuration in each of the property files accessible and usable. This causes the jobs to be automatically loaded and scheduled if they appear in a property file
|
||||
*/
|
||||
@Component
|
||||
@Getter
|
||||
@Setter
|
||||
|
||||
@@ -11,6 +11,9 @@ import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Bean responsible to setup the scheduler factory, because we need a custom data source and the quartz support needs to be aware of the application context.
|
||||
*/
|
||||
@Configuration
|
||||
public class SchedulerConfig {
|
||||
|
||||
@@ -34,6 +37,8 @@ public class SchedulerConfig {
|
||||
SchedulerFactoryBean factory = new SchedulerFactoryBean();
|
||||
factory.setOverwriteExistingJobs(true);
|
||||
factory.setDataSource(dataSource);
|
||||
// we should not startup automatically, because some jobs rely on discord
|
||||
// and they fail if the web socket connection is not yet established
|
||||
factory.setAutoStartup(false);
|
||||
factory.setQuartzProperties(properties);
|
||||
factory.setJobFactory(jobFactory);
|
||||
|
||||
@@ -3,6 +3,11 @@ package dev.sheldan.abstracto.scheduling.config;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
/**
|
||||
* Loads the property file responsible to configure the scheduling application.
|
||||
* This contains elements like database connection configuration, whether or not the tables should be created.
|
||||
* or the amount of threads.
|
||||
*/
|
||||
@Configuration
|
||||
@PropertySource("classpath:scheduling.properties")
|
||||
public class SchedulingProperties {
|
||||
|
||||
@@ -14,10 +14,24 @@ import static org.quartz.SimpleScheduleBuilder.*;
|
||||
import static org.quartz.CronScheduleBuilder.*;
|
||||
import static org.quartz.TriggerBuilder.*;
|
||||
|
||||
/**
|
||||
* Bean used to create the different types of jobs supported. The jobs include cron jobs and one-time jobs.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class QuartzConfigFactory {
|
||||
|
||||
/**
|
||||
* Creates a job according to the given configuration. This is the most detailed configuration. And is used when setting up the job on startup.
|
||||
* @param jobClass The class object of the job to be executed. Needs to extend {@link QuartzJobBean}.
|
||||
* @param isDurable Whether or not the job should be stored in the database, even though there are no triggers pointing to it. This is needed for
|
||||
* one time jobs, because they might not have any immediate execution scheduled.
|
||||
* @param context The spring application context for the job
|
||||
* @param jobName The name of the job to be used for triggers in order to find the job
|
||||
* @param jobGroup The group of the job to be used for triggers in order to find the job
|
||||
* @param requestsRecovery Whether or not the job should be executed again, if the scheduling application crashes.
|
||||
* @return The created description of the job according to the parameters
|
||||
*/
|
||||
public JobDetail createJob(Class<? extends QuartzJobBean> jobClass, boolean isDurable,
|
||||
ApplicationContext context, String jobName, String jobGroup, boolean requestsRecovery) {
|
||||
|
||||
@@ -37,6 +51,13 @@ public class QuartzConfigFactory {
|
||||
return factoryBean.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a trigger for a cron job according to a given cron expression and schedules the job to be started at the given time.
|
||||
* @param startTime The time the job should be active
|
||||
* @param cronExpression The cron expression used for the job.
|
||||
* @throws RuntimeException If the cron expression is not a valid expression.
|
||||
* @return The {@link CronTrigger} representing the cron expression
|
||||
*/
|
||||
public CronTrigger createBasicCronTrigger(Date startTime, String cronExpression) {
|
||||
return newTrigger()
|
||||
.withSchedule(cronSchedule(cronExpression).inTimeZone(TimeZone.getTimeZone("UTC")).withMisfireHandlingInstructionDoNothing())
|
||||
@@ -44,6 +65,16 @@ public class QuartzConfigFactory {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a detailed cron trigger with the given cron expression and start date for a job specifically.
|
||||
* It is also possible to directly provided parameters for the given job, which are then available within the job.
|
||||
* @param jobName The name of the job to schedule
|
||||
* @param jobGroup The group of the job to schedule
|
||||
* @param startTime The start time at which the job should start to execute
|
||||
* @param cronExpression The cron expression which represents at which times the job should execute
|
||||
* @param jobDataMap The {@link JobDataMap} containing parameters available to the job
|
||||
* @return The {@link CronTrigger} which can be used to directly schedule the job in the {@link Scheduler}
|
||||
*/
|
||||
public CronTrigger createBasicCronTrigger(String jobName, String jobGroup, Date startTime, String cronExpression, JobDataMap jobDataMap) {
|
||||
return newTrigger()
|
||||
.withSchedule(cronSchedule(cronExpression).inTimeZone(TimeZone.getTimeZone("UTC")).withMisfireHandlingInstructionDoNothing())
|
||||
@@ -53,6 +84,11 @@ public class QuartzConfigFactory {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple trigger, which executes exactly once at the given time
|
||||
* @param startTime The {@link Date} object containing the time at which a job should execute at
|
||||
* @return The {@link Trigger} object necessary in order to schedule a job
|
||||
*/
|
||||
public Trigger createSimpleOnceOnlyTrigger(Date startTime) {
|
||||
return newTrigger()
|
||||
.startAt(startTime)
|
||||
@@ -60,6 +96,14 @@ public class QuartzConfigFactory {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple one time trigger for a specific job with the provided parameters
|
||||
* @param jobName The name of the job to execute
|
||||
* @param jobGroup The group of the job to execute
|
||||
* @param startTime The time at which the job should be executed
|
||||
* @param jobDataMap The {@link JobDataMap} containing the parameters which should be available for the job
|
||||
* @return The {@link Trigger} containing the given parameters, read to be scheduled with {@link Scheduler}
|
||||
*/
|
||||
public Trigger createOnceOnlyTriggerForJob(String jobName, String jobGroup, Date startTime, JobDataMap jobDataMap) {
|
||||
return newTrigger()
|
||||
.startAt(startTime)
|
||||
|
||||
@@ -7,6 +7,11 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class SchedulerJobConverter {
|
||||
|
||||
/**
|
||||
* Converts a {@link SchedulerJobProperties} instance to a usable {@link SchedulerJob} instance
|
||||
* @param properties The instance directly coming from a property file
|
||||
* @return A instanc eof {@link SchedulerJob} which represents an instance from the database
|
||||
*/
|
||||
public SchedulerJob fromJobProperties(SchedulerJobProperties properties) {
|
||||
return SchedulerJob
|
||||
.builder()
|
||||
|
||||
@@ -6,6 +6,9 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
|
||||
|
||||
/**
|
||||
* Factory extension to make it possible to auto wire jobbeans
|
||||
*/
|
||||
public class SchedulerJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
|
||||
|
||||
private AutowireCapableBeanFactory beanFactory;
|
||||
|
||||
@@ -3,16 +3,37 @@ package dev.sheldan.abstracto.scheduling.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* The properties which are available to be configured via a property file
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SchedulerJobProperties {
|
||||
/**
|
||||
* The name of the job. Necessary to identify the job.
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* The group in which the job should reside. Necessary to identify the job.
|
||||
*/
|
||||
private String group;
|
||||
/**
|
||||
* If the job executes on a cron schedule, this should contain the cron expression for this. If it is a one-time job, this needs to be null.
|
||||
*/
|
||||
private String cronExpression;
|
||||
/**
|
||||
* The absolute class name of the job bean extending {@link org.springframework.scheduling.quartz.QuartzJobBean} which should be executed
|
||||
*/
|
||||
private String clazz;
|
||||
/**
|
||||
* Whether or not the job is active, and should be scheduled.
|
||||
*/
|
||||
private Boolean active;
|
||||
/**
|
||||
* Whether or not the job should be re-tried in an recovery of fail over situation.
|
||||
*/
|
||||
private Boolean recovery;
|
||||
}
|
||||
@@ -3,14 +3,29 @@ package dev.sheldan.abstracto.scheduling.repository;
|
||||
import dev.sheldan.abstracto.scheduling.model.database.SchedulerJob;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.QueryHints;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.persistence.QueryHint;
|
||||
|
||||
/**
|
||||
* Repository repsonsible to access the stored job configuration in the database
|
||||
*/
|
||||
@Repository
|
||||
public interface SchedulerJobRepository extends JpaRepository<SchedulerJob, Long> {
|
||||
|
||||
/**
|
||||
* Finds whether or not the job identified by the name exists in the database
|
||||
* @param name The name of the job to check for existence
|
||||
* @return Boolean variable representing whether or not the job identified by the name exists.
|
||||
*/
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
boolean existsByName(String name);
|
||||
|
||||
/**
|
||||
* Finds a job identified by the name
|
||||
* @param name The name of the job to search for
|
||||
* @return The found {@link SchedulerJob} instance by the name
|
||||
*/
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
SchedulerJob findByName(String name);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import org.quartz.spi.InstanceIdGenerator;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Generates the ID used for triggers etc. The implementation uses a {@link UUID} which is then stored and identifies the instance
|
||||
*/
|
||||
public class IdGenerationService implements InstanceIdGenerator {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -57,6 +57,8 @@ public class SchedulerServiceBean implements SchedulerService {
|
||||
boolean recurringJob = isRecurringJob(schedulerJob);
|
||||
jobDetail = scheduleCreator.createJob((Class<? extends QuartzJobBean>) Class.forName(schedulerJob.getClazz()),
|
||||
!recurringJob, context, schedulerJob.getName(), schedulerJob.getGroupName(), schedulerJob.isRecovery());
|
||||
// if its a cron job, we can schedule it directly, otherwise we just make the scheduler aware of its existance
|
||||
// and trigger it later
|
||||
if(recurringJob) {
|
||||
Trigger trigger = scheduleCreator.createBasicCronTrigger(new Date(),
|
||||
schedulerJob.getCronExpression());
|
||||
@@ -95,11 +97,11 @@ public class SchedulerServiceBean implements SchedulerService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unScheduleJob(String jobName) {
|
||||
public boolean unScheduleJob(String triggerKey) {
|
||||
try {
|
||||
return schedulerFactoryBean.getScheduler().unscheduleJob(new TriggerKey(jobName));
|
||||
return schedulerFactoryBean.getScheduler().unscheduleJob(new TriggerKey(triggerKey));
|
||||
} catch (SchedulerException e) {
|
||||
log.error("Failed to un-schedule job - {}", jobName, e);
|
||||
log.error("Failed to un-schedule job - {}", triggerKey, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -159,18 +161,6 @@ public class SchedulerServiceBean implements SchedulerService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String startCronJobWithParameters(String name, String group, JobDataMap dataMap, String cronExpression) {
|
||||
Trigger cronTrigger = scheduleCreator.createBasicCronTrigger(name, group, new Date(), cronExpression, dataMap);
|
||||
try {
|
||||
schedulerFactoryBean.getScheduler().scheduleJob(cronTrigger);
|
||||
return cronTrigger.getKey().getName();
|
||||
} catch (SchedulerException e) {
|
||||
log.error("Failed to start new job - {}", name, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopTrigger(String triggerKey) {
|
||||
try {
|
||||
|
||||
@@ -28,6 +28,9 @@ public class SchedulerStartupService {
|
||||
@Autowired
|
||||
private SchedulerJobConverter schedulerJobConverter;
|
||||
|
||||
/**
|
||||
* Loads the job definitions from the property file and schedules them, if the job does not exist yet.
|
||||
*/
|
||||
@EventListener
|
||||
@Transactional
|
||||
public void handleContextRefreshEvent(ContextRefreshedEvent ctxStartEvt) {
|
||||
|
||||
@@ -16,6 +16,7 @@ public class SchedulerJobManagementServiceBean {
|
||||
private SchedulerJobRepository repository;
|
||||
|
||||
public SchedulerJob createOrUpdate(SchedulerJob job) {
|
||||
// TODO add group to job search
|
||||
if(repository.existsByName(job.getName())) {
|
||||
SchedulerJob byName = repository.findByName(job.getName());
|
||||
byName.setActive(job.isActive());
|
||||
|
||||
@@ -2,11 +2,14 @@ package dev.sheldan.abstracto.scheduling.model.database;
|
||||
|
||||
|
||||
import lombok.*;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The scheduler job instance according to the properties stored in the database. This is needed in order to have a
|
||||
* reference of the jobs which *can* be scheduled.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@@ -20,16 +23,34 @@ public class SchedulerJob {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* The name of the job
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The group of the job
|
||||
*/
|
||||
private String groupName;
|
||||
|
||||
/**
|
||||
* The absolute path of a class extending {@link org.springframework.scheduling.quartz.QuartzJobBean} which should be executed by this job
|
||||
*/
|
||||
private String clazz;
|
||||
|
||||
/**
|
||||
* If the job should be executed based on a cron expression, this contains this expression. If it is a one-time job this needs to be null.
|
||||
*/
|
||||
private String cronExpression;
|
||||
|
||||
/**
|
||||
* Whether or not the job is active and available to be scheduled.
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* Whether or not the job should be re-tried in an recovery of fail over situation.
|
||||
*/
|
||||
private boolean recovery;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,16 +6,76 @@ import org.quartz.JobDataMap;
|
||||
import java.util.Date;
|
||||
|
||||
public interface SchedulerService {
|
||||
/**
|
||||
* Starts all the currently active and available jobs from the database with their respective configuration
|
||||
*/
|
||||
void startScheduledJobs();
|
||||
|
||||
/**
|
||||
* Schedules the given {@link SchedulerJob} instance directly
|
||||
* @param job The job to schedule
|
||||
*/
|
||||
void scheduleJob(SchedulerJob job);
|
||||
|
||||
/**
|
||||
* Updates an already scheduled job, with the same name and group, with the new {@link SchedulerJob} configuration
|
||||
* @param job The new configuration of the job to use. The name and the group of the job to update are taken from this object as well.
|
||||
* @param startDate The date at which this scheduled job should start executing
|
||||
*/
|
||||
void updateJob(SchedulerJob job, Date startDate);
|
||||
boolean unScheduleJob(String jobName);
|
||||
|
||||
/**
|
||||
* Removes a job from the scheduler.
|
||||
* @param triggerKey The key of the trigger to unschedule
|
||||
* @return if the job was found and unscheduled
|
||||
*/
|
||||
boolean unScheduleJob(String triggerKey);
|
||||
|
||||
/**
|
||||
* Deletes the job from the scheduler.
|
||||
* @param job The {@link SchedulerJob} instance containing the configuration of the job to remove
|
||||
* @return fi the job was found and deleted
|
||||
*/
|
||||
boolean deleteJob(SchedulerJob job);
|
||||
|
||||
/**
|
||||
* Pauses the given job in the scheduler
|
||||
* @param job The {@link SchedulerJob} instance containing the configuration of the job to pause
|
||||
* @return fi the job was found and paused
|
||||
*/
|
||||
boolean pauseJob(SchedulerJob job);
|
||||
|
||||
/**
|
||||
* Continues the job in the scheduler.
|
||||
* @param job The {@link SchedulerJob} instance containing the configuration of the job to continue
|
||||
* @return fi the job was found and continued
|
||||
*/
|
||||
boolean continueJob(SchedulerJob job);
|
||||
/**
|
||||
* Executes the job directly in the scheduler.
|
||||
* @param job The {@link SchedulerJob} instance containing the configuration of the job to execute directly
|
||||
* @return fi the job was found and executed directly
|
||||
*/
|
||||
boolean executeJob(SchedulerJob job);
|
||||
|
||||
/**
|
||||
* Executes the job identified by name and group with the given {@link JobDataMap} as parameters on the given {@link Date}
|
||||
* @param name The name of the job to execute
|
||||
* @param group The group of the job to execute
|
||||
* @param dataMap The {@link JobDataMap} made available to the group
|
||||
* @param date The {@link Date} at which the job should be execute at.
|
||||
* @return The trigger key which triggers the job at the given date
|
||||
*/
|
||||
String executeJobWithParametersOnce(String name, String group, JobDataMap dataMap, Date date);
|
||||
String startCronJobWithParameters(String name, String group, JobDataMap dataMap, String cronExpression);
|
||||
|
||||
/**
|
||||
* Stops the trigger identified by the trigger key.
|
||||
* @param triggerKey The key of the trigger to stop
|
||||
*/
|
||||
void stopTrigger(String triggerKey);
|
||||
|
||||
/**
|
||||
* Actually starts the scheduler.
|
||||
*/
|
||||
void startScheduler();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user