diff --git a/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SampleJob.java b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SampleJob.java index 9a5a47422..e5f7644c2 100644 --- a/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SampleJob.java +++ b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SampleJob.java @@ -1,12 +1,14 @@ package com.scheduler.quartz.job; import com.scheduler.quartz.service.OddEvenService; +import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.stereotype.Component; @Component +@DisallowConcurrentExecution public class SampleJob implements Job { private final OddEvenService oddEvenService; diff --git a/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SchedulerRegistrationService.java b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SchedulerRegistrationService.java index 8944f23e9..8b2ae6d2b 100644 --- a/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SchedulerRegistrationService.java +++ b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/job/SchedulerRegistrationService.java @@ -2,6 +2,7 @@ import static org.quartz.DateBuilder.futureDate; import static org.quartz.JobBuilder.newJob; +import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import static org.quartz.TriggerBuilder.newTrigger; import org.quartz.*; @@ -14,18 +15,23 @@ public class SchedulerRegistrationService { @Bean JobDetail registerOddJob() { return newJob(SampleJob.class) - .withIdentity("sample-job") + .withIdentity("sample-job", "sample-group") .usingJobData("jobName", "odd") .storeDurably() + .requestRecovery() .build(); } @Bean Trigger triggerOddJob(JobDetail registerOddJob) { return newTrigger() - .withIdentity("trigger-sample-job") + .withIdentity("trigger-sample-job", "sample-group") .forJob(registerOddJob.getKey()) - .startAt(futureDate(5, DateBuilder.IntervalUnit.SECOND)) + .startAt(futureDate(10, DateBuilder.IntervalUnit.SECOND)) + .withSchedule(simpleSchedule() + .withIntervalInSeconds(5) // Run every 2 seconds + .repeatForever() + .withMisfireHandlingInstructionFireNow()) .build(); } } diff --git a/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/model/response/JobStatus.java b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/model/response/JobStatus.java new file mode 100644 index 000000000..3f1c51f0d --- /dev/null +++ b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/model/response/JobStatus.java @@ -0,0 +1,3 @@ +package com.scheduler.quartz.model.response; + +public record JobStatus(String jobName, boolean completed) {} diff --git a/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/service/JobsService.java b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/service/JobsService.java new file mode 100644 index 000000000..7a52710da --- /dev/null +++ b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/service/JobsService.java @@ -0,0 +1,52 @@ +package com.scheduler.quartz.service; + +import com.scheduler.quartz.model.response.JobStatus; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; +import org.quartz.*; +import org.quartz.impl.matchers.GroupMatcher; +import org.quartz.utils.Key; +import org.springframework.stereotype.Service; + +@Service +public class JobsService { + + private final Scheduler scheduler; + private final String groupName = "sample-group"; + + public JobsService(Scheduler scheduler) { + this.scheduler = scheduler; + } + + public boolean deleteJob(String id) throws SchedulerException { + JobKey jobKey = new JobKey(id, groupName); + return scheduler.deleteJob(jobKey); + } + + public List getJobs() throws SchedulerException { + return scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName)).stream() + .map(Key::getName) + .sorted(Comparator.naturalOrder()) + .collect(Collectors.toList()); + } + + public List getJobsStatuses() throws SchedulerException { + LinkedList list = new LinkedList<>(); + for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) { + JobDetail jobDetail = scheduler.getJobDetail(jobKey); + List triggers = scheduler.getTriggersOfJob(jobDetail.getKey()); + for (Trigger trigger : triggers) { + Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); + if (Trigger.TriggerState.COMPLETE.equals(triggerState)) { + list.add(new JobStatus(jobKey.getName(), true)); + } else { + list.add(new JobStatus(jobKey.getName(), false)); + } + } + } + list.sort(Comparator.comparing(JobStatus::jobName)); + return list; + } +} diff --git a/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/web/controller/JobsController.java b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/web/controller/JobsController.java new file mode 100644 index 000000000..3610b0086 --- /dev/null +++ b/scheduler/boot-scheduler-quartz/src/main/java/com/scheduler/quartz/web/controller/JobsController.java @@ -0,0 +1,33 @@ +package com.scheduler.quartz.web.controller; + +import com.scheduler.quartz.model.response.JobStatus; +import com.scheduler.quartz.service.JobsService; +import java.util.List; +import org.quartz.SchedulerException; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/jobs") +public class JobsController { + + private final JobsService jobsService; + + public JobsController(JobsService jobsService) { + this.jobsService = jobsService; + } + + @GetMapping + List getJobs() throws SchedulerException { + return jobsService.getJobs(); + } + + @GetMapping("/statuses") + List getJobsStatuses() throws SchedulerException { + return jobsService.getJobsStatuses(); + } + + @DeleteMapping("/{id}") + boolean deleteJob(@PathVariable String id) throws SchedulerException { + return jobsService.deleteJob(id); + } +} diff --git a/scheduler/boot-scheduler-quartz/src/main/resources/application.properties b/scheduler/boot-scheduler-quartz/src/main/resources/application.properties index 5a89c37d0..7d6fae376 100644 --- a/scheduler/boot-scheduler-quartz/src/main/resources/application.properties +++ b/scheduler/boot-scheduler-quartz/src/main/resources/application.properties @@ -28,6 +28,7 @@ spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true spring.quartz.job-store-type=jdbc -spring.quartz.jdbc.initialize-schema=always +#spring.quartz.jdbc.initialize-schema=always +spring.quartz.properties.org.quartz.jobStore.isClustered=true spring.quartz.properties.org.quartz.jobStore.useProperties=true spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate diff --git a/scheduler/boot-scheduler-quartz/src/main/resources/db/changelog/db.changelog-master.yaml b/scheduler/boot-scheduler-quartz/src/main/resources/db/changelog/db.changelog-master.yaml index 7e9e64aa4..303312106 100644 --- a/scheduler/boot-scheduler-quartz/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/scheduler/boot-scheduler-quartz/src/main/resources/db/changelog/db.changelog-master.yaml @@ -2,4 +2,16 @@ databaseChangeLog: - includeAll: path: migration/ errorIfMissingOrEmpty: true - relativeToChangelogFile: true \ No newline at end of file + relativeToChangelogFile: true + + - changeSet: + dbms: postgresql + id: create-spring-quartz-metadata + author: raja + changes: + - sqlFile: + encoding: UTF-8 + path: classpath:/org/quartz/impl/jdbcjobstore/tables_postgres.sql + relativeToChangelogFile: false + splitStatements: true + stripComments: true \ No newline at end of file