Easy Way to Configure Quartz Scheduler with Spring Boot – Example With Source Code
Quartz Scheduler is a widely accepted and used open-source job scheduling library. This library can be integrated with all types of Java applications. Using this, you can convert your simple java components into a job that you can schedule and run as per your need. The library supports various storage strategies like RAM, RDBMS, etc.
On top of this, Quartz supports JTA transactions and clustering which comes in very handy when you want to deploy your application to production servers. We have earlier published an article for using Quartz in a standalone application.
Configure Quartz Scheduler with Spring Boot:
Here in this article, we will see how we can configure Spring Boot and Quartz. We will create a Spring Boot Quartz Scheduler application with MySQL, as a data store for our Quartz jobs and triggers.
Software used in this example
- Spring Boot 1.4.1.RELEASE
- Java 8
- Quartz 2.2.1
- MySQL
- Maven
- Eclipse
Demo Project Structure
The project will look like below in your Eclipse IDE
Along with Spring annotations, I am using xml based configuration to setup data source and entity manager for this example. To configure Quartz for your Spring Boot application, you need to add below dependency to your pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> |
As we are using MySQL as our database, we need to download quartz distributable and use the table structures that they have defined for MySQL. Once you have downloaded and executed the sql in your environment, the table will look like as below
This is our Application Start Point. You can see that I am using Spring Boot auto configuration capabilities here and at the same time I am importing my xml configuration as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.opencodez; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ImportResource; @SpringBootApplication @ImportResource({ "classpath:dao-context.xml" }) public class QuartzDemoApplication { public static void main(String[] args) { SpringApplication.run(QuartzDemoApplication.class, args); } } |
We are definingĀ a extra configuration class using annotation @Configuration that will do all required setup for Quartz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
/** * */ package com.opencodez.configuration; import java.io.IOException; import java.util.List; import java.util.Properties; import javax.sql.DataSource; import org.quartz.JobDetail; import org.quartz.SimpleTrigger; import org.quartz.Trigger; import org.quartz.spi.JobFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; import com.opencodez.util.AppUtil; /** * @author pavan.solapure * */ @Configuration @ConditionalOnProperty(name = "quartz.enabled") public class ConfigureQuartz { @Autowired List<Trigger> listOfTrigger; @Bean public JobFactory jobFactory(ApplicationContext applicationContext) { AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } @Bean public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource, JobFactory jobFactory) throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setOverwriteExistingJobs(true); factory.setAutoStartup(true); factory.setDataSource(dataSource); factory.setJobFactory(jobFactory); factory.setQuartzProperties(quartzProperties()); // Here we will set all the trigger beans we have defined. if (!AppUtil.isObjectEmpty(listOfTrigger)) { factory.setTriggers(listOfTrigger.toArray(new Trigger[listOfTrigger.size()])); } return factory; } @Bean public Properties quartzProperties() throws IOException { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties")); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } public static SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs) { SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean(); factoryBean.setJobDetail(jobDetail); factoryBean.setStartDelay(0L); factoryBean.setRepeatInterval(pollFrequencyMs); factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); // in case of misfire, ignore all missed triggers and continue : factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT); return factoryBean; } // Use this method for creating cron triggers instead of simple triggers: public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) { CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); factoryBean.setJobDetail(jobDetail); factoryBean.setCronExpression(cronExpression); factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); return factoryBean; } public static JobDetailFactoryBean createJobDetail(Class jobClass) { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); factoryBean.setJobClass(jobClass); // job has to be durable to be stored in DB: factoryBean.setDurability(true); return factoryBean; } } |
You can see that above I am creating different factory beans, that will be used to create jobs,that can be run by either simple trigger or cron trigger. Also we are specifying the quartz properties file, which will have different parameters to that are specific to quartz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceId = AUTO org.quartz.scheduler.makeSchedulerThreadDaemon = true #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.makeThreadsDaemons = true org.quartz.threadPool.threadCount: 20 org.quartz.threadPool.threadPriority: 5 #============================================================================ # Configure JobStore #============================================================================ org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = false org.quartz.jobStore.dataSource = myDs org.quartz.jobStore.misfireThreshold = 25000 #============================================================================ # Configure Datasources #============================================================================ org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/localdb org.quartz.dataSource.myDS.user = lessroot org.quartz.dataSource.myDS.password = lessroot org.quartz.dataSource.myDS.maxConnections = 5 org.quartz.dataSource.myDS.validationQuery = select 1 |
Also please note that, we are configuring the Quartz based on a property in our application.properties file. The property you can find on head of the class. If this is set to trueĀ then only we will configureĀ Quartz, else we will skip this configuration.
Now we are all set to define our first Job.Ā The example below shows youĀ a Job configured with Simple Trigger
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
/** * */ package com.opencodez.quartz.jobs; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; import org.springframework.stereotype.Component; import com.opencodez.configuration.ConfigureQuartz; import com.opencodez.util.AppLogger; /** * @author pavan.solapure * */ @Component @DisallowConcurrentExecution public class JobWithSimpleTrigger implements Job { private final static AppLogger logger = AppLogger.getInstance(); @Value("${cron.frequency.jobwithsimpletrigger}") private long frequency; @Override public void execute(JobExecutionContext jobExecutionContext) { logger.info("Running JobWithSimpleTrigger | frequency {}", frequency); } @Bean(name = "jobWithSimpleTriggerBean") public JobDetailFactoryBean sampleJob() { return ConfigureQuartz.createJobDetail(this.getClass()); } @Bean(name = "jobWithSimpleTriggerBeanTrigger") public SimpleTriggerFactoryBean sampleJobTrigger(@Qualifier("jobWithSimpleTriggerBean") JobDetail jobDetail) { return ConfigureQuartz.createTrigger(jobDetail,frequency); } } |
Please make sure that the beanĀ names for Job and Trigger we define here are unique and referenced correctly. You can define as many jobs as you want in similar fashion and they will be scheduled automatically. NoĀ other configuration is needed. Thanks to SpringĀ IOC, below code willĀ look for all the Triggers that are defined asĀ beans and willĀ autowire them in a list which can be supplied to scheduler.Ā Please check above ConfigureQuartz.java for code.
Lastly you can see below the output/console for the jobs that we have scheduled in our example.
Update – Adding DI to Spring Boot Quartz Scheduler Job Class
Few of our fellow developers were facing issues when tried to use @Inject in the Job Class. I could not pin point the root cause for that, but I found a solution. In earlier examples, I have used @Qualifier to inject JobDetail object and when we try to use Dependency Injection (Inject, Autowired) in the job class it failed. So instead we used @Qualifier to injectĀ JobDetailFactoryBean instance. From this factory bean we then pulled JobDetails for further processing. Code Ref-
1 2 3 4 5 6 7 8 9 10 11 12 |
@Inject private ArbitraryDependency fieldInjectDependency; @Bean(name = "jobWithDITesterBean") public JobDetailFactoryBean sampleJob() { return ConfigureQuartz.createJobDetail(this.getClass()); } @Bean(name = "jobWithDITesterBeanTrigger") public CronTriggerFactoryBean sampleJobTrigger(@Qualifier("jobWithDITesterBean") JobDetailFactoryBean jdfb ) { return ConfigureQuartz.createCronTrigger(jdfb.getObject(), frequency); } |
You can download and run the code from GitHub.
Hi Pavan,
I want to force stop a quartz running job but I can’t. I used the scheduler’s interrupt method but it’s not working.
Please suggest to me the correct way.
Hi Pawan,
I have implemented Quartz in a spring boot app. I’m not able to interrupt a running trigger. Below is the code for interrupt the running jobs.
List currentlyExecuting = scheduler.getCurrentlyExecutingJobs();
for (JobExecutionContext jobExecutionContext : currentlyExecuting) {
if(jobExecutionContext.getJobDetail().getKey().getName().equals(“JobName”)){
scheduler.interrupt(jobExecutionContext.getJobDetail().getKey());
System.out.println(“stoppeed”);
}
**************
Here is the code for executing my business logic.
public class SimpleJob extends QuartzJobBean implements InterruptableJob
{
@SuppressWarnings(“unused”)
private volatile boolean toStopFlag = true;
@Autowired
SchedulerFactoryBean schedulerFactoryBean;
@Autowired
SendAndReciveDataOverInOutCon sendAndReciveDataOverInOutCon;
@Override
public void executeInternal(JobExecutionContext jobExecutionContext)
throws JobExecutionException
{
Scheduler scheduler = schedulerFactoryBean.getScheduler();
sendAndReciveDataOverInOutCon.fetchAndSendDataOverInOutConnections(jobExecutionContext,
scheduler, true);
}
@Override
public void interrupt() throws UnableToInterruptJobException
{
System.out.println(“Stopping thread… “);
toStopFlag = false;
}
}
Please help me to interrupt the running triggers.
factory.setDataSource(dataSource);
What is this DataRouce?
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
And what is the DataSource from Quartz.properties?
Should be both one and same?
The problem is with the database configurations, like org.quartz.dataSource.quartzDS.driver, URL, user, password which you have defined. Please check that these configs are correct and as suggested by Pavan, check if you are able to make a DB call to the Database you have created for Quartz.
Can anyone please help me in this.:-
“Write a scheduled method in a spring boot app that runs automatically after every 10 seconds”.
Thank You
https://www.mkyong.com/jsf2/how-to-trigger-a-quartz-job-manually-jsf-2-example/
i need to get same output like the link provided can u provide me any examples
Hi
Im using quartz scheduler in one of our application , ours is poller based apps, it will poll certain tables on pre configured intervals. During the process , system will update the last poll time to the quarts table.
There are certain scenario we may have to update th last poll time for each table , what we thought is provide an endpoint and leverage it to updated the time details.
But the challenge here is , we have to get job schedule context in Rest controller.
Is there a way to get Jobschedule contect in rest controller
Hi Pavan,
Thank You Pavan for a nice and informative article.
I am using QuartzScheduler in a SpringBoot App.
org.quartz-scheduler
quartz
While executing SpringBootApplication, I am getting below exception :
Scheduler class: ‘org.quartz.core.QuartzScheduler’ – running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool ‘org.quartz.simpl.SimpleThreadPool’ – with 5 threads.
Using job-store ‘org.quartz.simpl.RAMJobStore’ – which does not support persistence. and is not clustered.
Will you be able to help me to know possible causes for this?
Thank You.
Hi Pavan,
I am trying to configure using the above example but my property value is not getting injected and every time i am getting null(cron.frequency.jobwithsimpletrigger).
Please suggest..
Thanks,
AJ
Hi Amit,
Have you annotated (e.g. @component) your class where you trying to access the property?
Pavan,
Thank you for the Excellent article!
Even after getting the latest code, the error persists:
[com/opencodez/configuration/ConfigureQuartz.class]: Invocation of init method failed; nested exception is org.quartz.SchedulerException: Trigger’s related Job’s name cannot be null
If I remove ‘JobWithCronTrigger.java’ application starts and the quartz tables also populated correctly.
Pleas suggest!
Hi Yogi,
Can you confirm in your local copy of JobWithCronTrigger.java that below method is as shown
@Bean(name = "jobWithCronTriggerBean")
public JobDetail sampleJob() {
return ConfigureQuartz.createJobDetail(this.getClass()).getObject();
}
Note the getObject call
I am getting the following exception : Factory method ‘jobFactory’ threw exception; nested exception is java.lang.ClassCastException: AutowiringSpringBeanJobFactory cannot be cast to org.quartz.spi.JobFactory
Hi Vishnu,
Are you using code as is or you changed any configuration?
We are facing an issue in which our quartz scheduler application is not getting triggered in the environment which has RDS. The same quartz scheduler application triggers as desired in our local environment.
We tried taking the dump of the DBs in the environment working with RDS into our local environment and found that the quartz scheduler triggers properly as desired.
Our quartz trigger is implemented as : the quartz trigger is stored in one of the tables in the RDS instance and it automatically fires at a point in time to run an application job.
Any information would be of great help.
Hi I am new to Quartz
getting error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘testController’: Unsatisfied dependency expressed through field ‘schedFactory’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘schedulerFactoryBean’ defined in class path resource [com/opencodez/configuration/ConfigureQuartz.class]: Invocation of init method failed; nested exception is org.quartz.SchedulerException: Trigger’s related Job’s name cannot be null
Please explaine me how to run this app
Thanks
SK
Hi SK,
I have got same error. If you have got the solutions please let me know.
Thanks,
Shubham
Hi Pavan,
I implemented quartz scheduler and its working in local environment, but when i move same code to qa , cron trigger is not working..! I got logs from qa/production environment like
schedulerFactoryBean_$_NON_CLUSTERED paused.
2018-08-28 12:52:17,160 INFO [org.springframework.jmx.export.annotation.AnnotationMBeanExporter] (Thread-96) Unregistering JMX-exposed beans on shutdown
org.springframework.scheduling.quartz.SchedulerFactoryBean] (Thread-96) Shutting down Quartz Schedulerorg.quartz.core.QuartzScheduler] (Thread-96) Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutting down.schedulerFactoryBean_$_NON_CLUSTERED paused.
schedulerFactoryBean_$_NON_CLUSTERED shutdown complete.
Any Idea about updation required in code or Any thoughts ?
Hi Pavan,
I strictly want to use Hibernate for my project. The quarts setup has .sql files in it. Do you know if there are Entity files for the 10-11 tables? If not, can you tell me step-wise procedure for using Quartz with Hibernate or link to an existing article?
Hi Pavan,
I am able to execute the example given by you but i am getting the message that Using job-store ‘org.quartz.simpl.RAMJobStore’ – which does not support persistence. and is not clustered.
I had to disable the auto configurations of data sources since app uses 2 schemas within Oracle DB.
Not able to find the way to create auto persistence for the Quartz tables please help.
Using Spring Boot 2 with Data Source configuration disabled.
Even tried with below 2 entries to application.properties.
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=always
Hi Chetan,
Is it possible for you to share more logs on my email address? pavan.solapure[@]gmai.com
Have sent you the console logs. Please check. Thanks.
Hey Pavan,
Have solved the issue with 2 schema by marking one of the datasource as @Primary. In the primary database i am able to see the quartz related tables.
Now facing other issue where if i inject my service inside the JobWithCronTrigger getting below error.My requirement is to write one service with in cron job to do some operation in DB.
Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug’ enabled.
2018-07-17 19:14:10.795 ERROR 19580 — [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method sampleJobTrigger in com.wlgore.cpd.job.JobWithCronTrigger required a bean of type ‘org.quartz.JobDetail’ that could not be found.
Action:
Consider defining a bean of type ‘org.quartz.JobDetail’ in your configuration.
Hi Chetan,
I had to tweak the function as below in JobWithCronTrigger.java to work the autowiring of service
@Bean(name = "jobWithCronTriggerBean")
public JobDetail sampleJob() {
return ConfigureQuartz.createJobDetail(this.getClass()).getObject();
}
Please take latest code from git and see if that works for you
Hi Pavan,
I implemented quartz scheduler and its working in local environment, but when i move same code to qa , cron trigger is not working..! I got logs from qa/production environment like
2018-08-28 12:52:16,885 INFO [org.springframework.context.support.DefaultLifecycleProcessor] (Thread-96) Stopping beans in phase 2147483647
2018-08-28 12:52:16,906 INFO [org.quartz.core.QuartzScheduler] (Thread-96) Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused.
2018-08-28 12:52:17,160 INFO [org.springframework.jmx.export.annotation.AnnotationMBeanExporter] (Thread-96) Unregistering JMX-exposed beans on shutdown
2018-08-28 12:52:17,248 INFO [io.undertow.servlet] (ServerService Thread Pool ā 9) Destroying Spring FrameworkServlet ādispatcherServletā
2018-08-28 12:52:17,249 INFO [io.undertow.servlet] (ServerService Thread Pool ā 9) Closing Spring root WebApplicationContext
2018-08-28 12:52:17,375 INFO [org.springframework.scheduling.quartz.SchedulerFactoryBean] (Thread-96) Shutting down Quartz Scheduler
2018-08-28 12:52:17,471 INFO [org.quartz.core.QuartzScheduler] (Thread-96) Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutting down.
2018-08-28 12:52:17,471 INFO [org.quartz.core.QuartzScheduler] (Thread-96) Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused.
2018-08-28 12:52:17,563 INFO [org.quartz.core.QuartzScheduler] (Thread-96) Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutdown complete.
Any Idea about updation required in code or Any thoughts ?
Hi Pavan, Great work! Really appreciate your work.
I am having difficulty in running the project. How to define tables in ‘localdb’
I dd something like this(below). I think I am missing something related to the database.
CREATE TABLE qrtz_simple_triggers (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
Hi Rohith,
You can find the tables from quartz directory. If you have already downloaded quartz package, you can find it in docs/dbTables. Choose the one as per your database. The GIT link for same is – https://github.com/quartznet/quartznet/tree/master/database/tables
Wow, Super fast reply. Thanks for helping out. I did that. I am using MySQL as my database. I have the same table like you did in ‘localdb’ now. It works flawlessly. Only thing I have to change was my database names to small letters. Thanks!
Fix: I Mean tables names in the database to lowercase.
Hi Pavan,
I am getting error when i autowire any service into multiple jobs. But if i keep autowire in only one of the job, it works no matter how many jobs i have. But if I autowire a service into second job. It fails. Any help would be appriciated
Is it still happening?
HI Pavan – Thx. Whether the same code can be used within clustered env as well, by setting the isclustered to true or is that any change in code for clustered env.
Hi Kumar,
Yes, you can use the same code with the required cluster settings recommended by Quartz.
Thanks Pavan. What my requirement is see my service inside node1 fails, then it will call the node2 to run automatically. Pls confirm whether node and service instance refer same in clustered env.
Hey , this is Nice tutorial . can you do some help. i have a requirement to just schedule a job dynamically with some parameter and it will never repeat again.There is any sample code for it.
Hi Archit,
The article already covers about scheduling a job dynamically. Regarding running it only once, I don’t think quartz has that option yet. But you can achieve that with some code patch. In the execute method of the job you want to run only once, you can check the previous run time. If that is non-null, then you can remove that job from the schedule. Sample code:
Date prevDate = jobExecutionContext.getPreviousFireTime();
if (null != prevDate) {
try {
logger.info("******* JOb ran once already @ {}.. remove it!!", prevDate);
Scheduler scheduler = jobExecutionContext.getScheduler();
scheduler.deleteJob(new JobKey("jobWithSimpleTriggerBean"));
} catch (SchedulerException e) {
e.printStackTrace();
}
return;
}
okay I got it . but what if i want to run multiple jobs of same type but with different parameter or different metadata.
You will have to configure multiple jobs unique bean names. Then follow same approach for all.
Hi Pavan,
Great work!
I have one doubt like
As you are reading the cron expression from properties
but I am looking for a solution where I can read this from DB instead
because reading from properties will reset the updated cron expression from property file on every time application starts.
Hi Anurag,
That would be possible. You need to make sure you load your properties from a database. You can refer one of article we have on that: How to Load Application Properties from Database
Let me know if this helps you.
Thanks
How can we schedule multiple jobs using the same scheduler? Do you have any code sample?
Hi Prasenjit, I don’t have any code sample, but I will try to provide soon.
I Have the same Alex’problem: org.springframework.beans.factory.NoSuchBeanDefinitionException, to multi Jobs. Could you expose the solution?
Hi Jesus,
I have added solution to our git repository. Please refer class JobWithDITester.java.
Not sure why, but when I use @Qualifier annotation for JobDetails it failed. So instead I injected JobDetailFactoryBean and pulled JobDetail object from it.
Now the @Inject and @Autowired works in Job class.
Let me know if this works for you.
What should I update in the current code to create cron trigger explicitly instead of creating just one trigger at the project start ?
Hey Pavan, Great tutorial, one of the best ones I came across in this topic. I have a requirement where we want to manage jobs dynamically as well. With Quartz, I understand scheduling can be dynamic. Our requirement is, if we have all the jobs in database, we just want our application to look at database and run jobs as per their schedule. Alert for failures etc. Do you know if there is a way to make jobs dynamic as well. We don’t want to roll code every time we need to add a job. Instead, give user UI ability to add job into the database and our application should just run the jobs per schedule. Any thoughts ? Thank you!
Hi Madhuri,
Thanks for stopping by and apologies for late response.
Ofcourse we can develop an UI for Adding a Job and Scheduling. This would require thorough knowledge about quartz scheduling, jobs and triggers. Also we need to have very tight validations and trained team to add jobs in your system.
Hi Pavan, thank you for your example, as it is, it seem to be working well for me.
However, is it possible to @Inject anything into a Job component? As soon as I try to @Inject a property into the class, everything is falling apart – I am getting org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘org.quartz.JobDetail’ available (this is when spring container tries to call public CronTriggerFactoryBean sampleJobTrigger() ).
Hi Alex,
Is it possible to send me the sample you are trying? You can send it to my gmail account pavan.solapure. I will have a look and get back to you.
hey, can you please comment on why do we need this ?
@ConditionalOnProperty(name = “quartz.enabled”) ? I dont even see this property in the quartz properties file so why use it ?
Hi Anil,
The annotation defined here is used to conditionally initialize the bean. The bean will get initialized only when quartz.enabled property in application.properties is set to true.
Hi Pavan, can you please help me understand AppUtil purpose and TXNID. I am not using end point to schedule and unschedule. Is TXNID solely for scheduling and unscheduling or is there a different purpose? thanks in advance
Hi Kay,
The TXNID is not related to schedule/unschedule. The AppUtil is there only to provide some generic and common functionalities if at all you want to use it.
Thanks Pavan. I am a little worried when refactoring.I completely got rid of constants and commented code in AppUtil that refers to these constants. Still not giving me problem.
I have set scheduler to 30 seconds and ran 2 instances and I could see a conflict – both ran the job [ 2 nodes in websphere]. This is a fail. I suspect it could be because each node creates bean and observed that as one node is about to finish the app starting process, the other was starting banner.
setOverwriteExistingJobs(true) – is this the cause?
Hi Kay,
It seems this setOverwriteExistingJobs(true) could be the culprit. I dont have right environment to test now. Is it possible for you to make it false and give it a try?
Hi Pavan,
I did set as false and it seems it is working without overwriting.
Great!
Possible Bug:
I created a project on similar lines and deployed on WebSphere tat has 2 nodes. Active Active. I could see in the logs that both were triggering at the same time. This is not every time, but it is defeating the purpose at times. The spring beans are creating the database rows in DB and can see a few seconds difference when starting. Is it that the bean created from one node is overwritten by the later one? please confirm if it is a possible scenario
Hi Pavan, All,
can someone explain what is the meaning of the below
@Autowired
List listOfTrigger;
As we have define our jobs and triggers as beans managed by Spring, due to this line spring will make sure to fill this list wit all the trigger bean.
Thanks for your quick response. The issue I have is to get another cron trigger job class working. So I created another class similar to existing cron trigger and it is failing at statup
this is fixed now. frequncy was coming as null, so moved Beans to Spring Boot main class.
Great Kay! Glad that the code is being referred š
Hi Pavan, I am having issue if I create another job with Cron Trigger. It is bean creation issue. Is it because you are using static method for create cron trigger in ConfigureQuartz?
HI, can this be a little simplified? Please help me understand why app-custom.properties is required?
Is it possible to move dao-context config to application.properties?
Hi Key,
You can skip the custom properties and use default properties file as well.
Yes, you can move dao context config to properties file. Just refer any sample database application on Spring Boot
Hi Pavan, Thanks for the reply. Do you have any pointers on how to get rid of dao-context.xml. I have no idea on how to move persistence unit into application.properties. can you help.
Hi, i added properties like
spring.datasource.dbcp.url
spring.datasource.dbcp.time-between-eviction-runs-millis
driver-class-name etc and removed import resource from boor app. Looks like it is ok. Is persistence.xml required?
Hi Pavan,
First of all, thanks for writing this article.
I followed your tutorial and also went through the code in github.
I would like to schedule jobs via API call rather that taking frequency/cron expressions from the properties file, can you tell me how the code changes to do that?
Basically, will it follow an entirely different approach or there is someway to dynamically set those values in Job files (which are annotated as @Component?
Thanks
You can do this using API call as well.
I have used @Component annotation for demo purpose, as I wanted to initialize all jobs on startup.
You can instantiate your job bean on receiving api call and you can accept job parameters from api and use them to setup your trigger.
Let me know if this works for you or need any help
Hi,Pavan,
Great Tutorial
I am also running through same problem,
I need to set trigger for n dynamic jobs on initialization.
Could you please share some code?
Hi Sushil
Please take the latest code base from Git. I have added new class DynamicJob and changed the TestController to schedule/unschedule job dynamically. Once you start the application hit url http://localhost:9090/schedule to schedule the job. Check console for logs that being printed from this job.
To unschedule, hit url http://localhost:9090/unschedule
Let me know if this works for you.
Thanks, it helped.
Hello. There I some issue. When I have one job all is good. But when I’ve added the second one – there all is broken.
Caused by: org.quartz.SchedulerException: Trigger’s related Job’s name cannot be null
at org.quartz.impl.triggers.AbstractTrigger.validate(AbstractTrigger.java:763)
at org.quartz.core.QuartzScheduler.scheduleJob(QuartzScheduler.java:915)
at org.quartz.impl.StdScheduler.scheduleJob(StdScheduler.java:258)
Hello Maxim,
Apologies for late reply. Have you checked that that you have given unique names to the Job Bean and referenced them correctly in the trigger?
same question, newest code from github exception, delete only left DynamicJob and JobWithSimpleTrigger is ok.
Hi Pavan
WE are trying to use the Quartz for DB2 10 version. but I dont see any delegate or the scripts for the DB2 10. Can I use the latest version Db2 9.5..Any pointers will be helpful.
Hi BharathyKannan,
If you dont see the table scripts for your version of DB2, then I would request you to use the latest available and change the scripts as per new version of database. I dont think any changes to the latest script would be required, as these are just create table scripts. So please try and let me know if this works out for you.
Hi ,
I used this sample to create a scheduler with springboot that runs every minute. It was working fine till now but suddenly quartz stop working silently in qa environment. When i see the state of trigger it shows blocked . When i restart my service quartz starts working again and after some time again it silently stops executing. Can you please assist in this??
Hi Bharat,
Is your job taking more than one minute to finish? It generally happens when the time taken by job is more than the frequency you have set for job.
Please check the time and set frequency accordingly. Let me know if this works for you.
Hi pavan,
Thanks for the reply. i will try the solution you suggested but i have one more concern we have marked scheduler thread as Daemon can this cause such issue because i have read that Daemon threads exists even when JVM is shut down so will that cause any issue if JVM is stopped and start again. Second thing that i like to ask is that on embedded tomcat shutdown will scheduler thread also shut down automatically because in your code i cannot find shut down code for quartz scheduler or is it managed automatically in springboot environment. Please let me know
Also one thing I noticed I left debugger three to four times in scheduler for more that 5 to 10 minutes but I am unable to regenerate this issue . Scheduler continue to run properly as we have already configured misfire instructions setting in quartz. So i think that this should not be a cause in production and QA environment also in case scheduler is taking more than a minute to execute
Hi Pavan,
I am facing the below error :-
Exception encountered during context initialization – cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘schedulerFactoryBean’ defined in class path resource [com/opencodez/configuration/ConfigureQuartz.class]: Invocation of init method failed; nested exception is org.quartz.JobPersistenceException: Failed to obtain DB connection from data source ‘springTxDataSource.schedulerFactoryBean’: java.sql.SQLException: Connections could not be acquired from the underlying database! [See nested exception: java.sql.SQLException: Connections could not be acquired from the underlying database!]
Currently all the table starting with QRTZ are empty.Can you please share the content of tables?
or tell me the way to fill the data in each table?
Thanks,
Saurav
Hi Sourav,
The error clearly indicates that database connection is not successful. Can you cross check if you have given correct credentials for your database?
The contents of QRTZ_ tables are automatically populated by quartz framework when you schedule a job.
So please look in to the database connection issue and you will be able run the project and you can also see data automatically filled in to QRTZ tables.
Great tutorial! I have been researching how to integrate Quartz, Spring Boot & Batch for a few days now. This seems to be the most complete tutorial for the Quartz portion. Do you have any plans to outline how to integrate Spring Batch as well?
Thanks Jeffrey. I will try and add one article on Spring Batch as well.
Hi Pavan, Can you please provide me the link of the article on Spring Batch integration with Quartz.
Hope this one you are asking?
https://www.opencodez.com/java/quartz-scheduler-with-spring-boot.htm
Hello Pavan is there a sample example where we could use the Quartz job with Job data. I am having hard time injecting a JobDataMap Object to the JobBean creator.
Hi Deepthi,
You can check the latest git repo – https://github.com/pavansolapure/opencodez-samples/tree/master/quartz-demo
I have tried to add one sample with JobDataMap. See if that helps you.
i don’t see the part where dumping table data details,sorry my mistake. But in your github proj,2 different username and password are used xml and properties filewhy is that??
actually iam a bit new to this scheduling and spring boot,referred your project for scheduling some column data from a table1 with a fixed interval of time the data must be copied to table2 which has same fields or child fields.
can you help me ??
Hi Akkil,
The quartz proprties file has typo. The password should be same at both the places , i.e. “lessroot””.
I have corrected that in GIT. Please correct and try to run the project. If you are able to run the job successfully then you can simply achieve the data copy from one table to other. If you have defined entity, then load all the data in list and repopulate objects for another table and commit them using entitymanager.
i just used in mysql also but i got the same error as above.
this is your pass in quartz.properties file,org.quartz.dataSource.myDS.password = pavan@acn
but in dao-context.xml lessroot
so please explain and i dont create any entity classes in my postgresql
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘schedulerFactoryBean’ defined in class path resource [com/opencodez/configuration/ConfigureQuartz.class]: Invocation of init method failed; nested exception is org.quartz.JobPersistenceException: Couldn’t retrieve trigger: ERROR: relation “qrtz_triggers” does not exist
i just changed database because iam using postgresql
I am assuming you have already created the quartz tables in your postgresql. Are they accessible to the user you are using?