mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-03-27 14:23:56 +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());
|
||||
|
||||
Reference in New Issue
Block a user