The requirements were, to be able to dynamically schedule jobs using Quartz. After looking at examples on the web I found most of the examples were of static scheduling. I want to create quartz job within a loop. Currently only one job is running. Please help me. My code is given below
while (iterator.hasNext()) {
JSONObject obj =iterator.next();
ISocialMediaPoller socialMediaObj=socialMeadiaObj.getPoller(obj);
String jobName = (String)obj.get("NAME");
// long rpo =(Long)obj.get("RPO");
JobDetail job = new JobDetail();
job.setName(jobName);
job.setJobClass(Pollersheduller.class);
//configure the scheduler time
SimpleTrigger trigger = new SimpleTrigger();
trigger.setName(jobName);
trigger.setStartTime(new Date(System.currentTimeMillis() + 1000));
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
trigger.setRepeatInterval(12345);
// socialMediaObj.execute();
//schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.getContext().put("socialMediaObj", socialMediaObj);
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
SchedulerContext schedulerContext = null;
try {
schedulerContext = context.getScheduler().getContext();
ISocialMediaPoller socialMediaObj=
(ISocialMediaPoller)schedulerContext.get("socialMediaObj");
socialMediaObj.execute();
} catch (SchedulerException e1) {
e1.printStackTrace();
}
I would suggest managing your jobs through the db , in case your server restarts you better persist the dynamically created quartz jobs.
Here is an example
#Service public class PersistentJobSchedulerJob {
private static Logger logger = Logger.getLogger("PersistentJobSchedulerJob");
#Autowired
private JobRepository jobRepository;
#Autowired
private MailService mailService;
#SuppressWarnings({ "rawtypes", "unchecked" })
#Scheduled(fixedRate=30000)
public void schedulePersistentJobs(){
List<JobData> jobsData= jobRepository.findAll();
logger.info("Retriving Jobs from Database and Scheduling One by One | Total Number of Jobs: "+jobsData.size());
try{
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
for(JobData jobData: jobsData){
JobDetail job = newJob(MailSenderJob.class)
.withIdentity(jobData.getJobName())
.usingJobData(getJobDataMap(jobData))
.build();
if(!jobData.getActive()){
logger.info("Deleting a Job");
scheduler.deleteJob(new JobKey(jobData.getJobName()));
continue;
}
if(scheduler.checkExists(new JobKey(jobData.getJobName()))){
logger.info("Rescheduling the Job");
Trigger oldTrigger = scheduler.getTrigger(new TriggerKey(jobData.getJobName()+"Trigger"));
TriggerBuilder tb = oldTrigger.getTriggerBuilder();
Trigger newTrigger = tb.withSchedule(simpleSchedule()
.withIntervalInMilliseconds(jobData.getRepeatInterval()).
repeatForever())
.build();
scheduler.rescheduleJob(oldTrigger.getKey(), newTrigger);
}else{
logger.info("Scheduling the Job");
scheduler.scheduleJob(job,getTrigger(jobData));
}
}
}catch (SchedulerException e) {
logger.error("Scheduler Exception : "+e.getMessage());
}
}
private JobDataMap getJobDataMap(JobData jobData) {
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("recipients", jobData.getRecipients());
jobDataMap.put("mailService", mailService);
return jobDataMap;
}
private Trigger getTrigger(JobData jobData){
SimpleTrigger simpleTrigger = newTrigger().withIdentity(jobData.getJobName()+"Trigger")
.startAt(jobData.getStartDateTime())
.withSchedule(simpleSchedule()
.withIntervalInMilliseconds(jobData.getRepeatInterval()).
repeatForever())
.build();
return simpleTrigger;
} }
The full source code can be found here: Job scheduling with Quartz example
Related
i have a class where i perform some activities, and i want to create a job that will handle this operation automatically, scheduled every x minutes for example.
I am using Quartz, this class implements Job, and in my driver class i'm creating my jobdetail, scheduler and trigger and then starting it. However, the job isn't being executed, log info :
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
The code for the scheduler in my driver class:
try {
JobDetail job = JobBuilder.newJob(TestMkFPMJob.class).withIdentity("TestMkFPMJob").build();
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(Integer.parseInt(strTimeSched)).repeatForever()).build();
SchedulerFactory schFactory = new StdSchedulerFactory();
Scheduler sch = schFactory.getScheduler();
sch.start();
sch.scheduleJob(job, trigger);
}
catch (SchedulerException e)
{
e.printStackTrace();
System.out.println("Scheduler Error");
}
With "TestMkFPMJob" being the job class where my operations are handled, and strTimeSched is already fetched and set as 120 fetched from
I've been looking for a similar issue but can't seem to find any tip to move forward, appreciate any.
Please note that this is my first time using Quartz/Job scheduling.
The log entry with NOT STARTED is misleading, as it is shown whenever a QuartzScheduler instance is created. It does not mean that the jobs are not running. It is written after the line Scheduler sch = schFactory.getScheduler(); is executed and the scheduler is started in the next line.
If I take your example and run it on my pc, it is working as designed:
public class Quartz {
public static void main(String[] args) {
try {
JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("myJob").build();
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(Integer.parseInt("10")).repeatForever()).build();
SchedulerFactory schFactory = new StdSchedulerFactory();
Scheduler sch = schFactory.getScheduler();
sch.start();
sch.scheduleJob(job, trigger);
}
catch (SchedulerException e)
{
e.printStackTrace();
System.out.println("Scheduler Error");
}
}
public static class MyJob implements Job {
#Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("runnning job");
}
}
}
public class CronTriggerApp {
public static void main(String[] args) {
try {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
JobDetail job = JobBuilder.newJob(Main.class)
.withIdentity("dummyJobName", "group1").build();
System.out.println(job);
Date startTime = DateBuilder.nextGivenSecondDate(null, 5);
System.out.println(startTime);
// run every 20 seconds infinite loop
CronTrigger crontrigger = TriggerBuilder
.newTrigger()
.withIdentity("TwentySec", "group1")
.startAt(startTime)
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("* * * ? * *"))//0 53 12 * * ? *
.build();
scheduler.start();
scheduler.scheduleJob(job, crontrigger);
//scheduler.shutdown();
} catch (SchedulerException se) {
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Main implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException
{
System.out.println("Trigger Starts.."+new Date());
System.out.println("ALL_OFF");
}
}
By using above code i can able to schedule cron job..but if want cancel the schedule time how can able to cancel or stop the schedule task?
can any one plz help me how can i stop or cancel the scheduled task?
You can expose an endpoint to interrupt it. And use the following function of scheduler to stop it.
scheduler.interrupt(jobDetail.getKey());
I am new to Spring Batch framework and quartz scheduler. My task is to schedule a new Spring Batch job dynamically using quartz scheduler. All new spring batch job's entries are in my database with trigger expression. Problem is that for every new spring batch job coming from database , we need to wrap it in quartz's scheduler job. so means as many spring batch job will be there that many batch job class should be there to wrap them and run by quartz scheduler.
quartz is storing all the job's and trigger entry into its own data base tables. which i have configure in config file. This job will always be quartz's job not spring batch job.
here is my main method, here i will write my data base connection code to find out new springbatch job name and trigger expression and will bind them with quartz schedular
public static void main(String[] args) {
try {
ApplicationContext context = new ClassPathXmlApplicationContext("quartz-context.xml");
JobLauncher launcher=(JobLauncher) context.getBean("jobLauncher");
JobLocator locator= (JobLocator) context.getBean("jobRegistry");
Scheduler schedulerFactoryBean=(Scheduler) context.getBean("quartzSchedulerFactoryBean");
JobDetail job = newJob(SpringBatchJob.class).withIdentity("myJob001", "group1").build();
Trigger trigger1 =newTrigger().withIdentity("myTrigger001", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();
schedulerFactoryBean.scheduleJob(job, trigger1);
schedulerFactoryBean.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
Here we can see that we have jobDetail which is quartz job and whose execute method is use to run spring batch job.
springBatchjob.java
public class SpringBatchJob implements Job {
private String jobName;
private String batchJob;
private JobLocator jobLocator;
private JobLauncher jobLauncher;
private File contentDirectory;
private String directoryPath = "inputFiles";
public void init(){
contentDirectory = new File(directoryPath);
}
boolean fileFound = false;
public void performJob(String str) {}
public String getJobName() {
return jobName;
}
public void setBatchJob(String batchJob) {
this.batchJob = batchJob;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public void setJobLocator(JobLocator jobLocator) {
this.jobLocator = jobLocator;
}
public void setJobLauncher(JobLauncher jobLauncher) {
this.jobLauncher = jobLauncher;
}
#Override
public void execute(JobExecutionContext arg0) throws org.quartz.JobExecutionException {
JobParameter jb= new JobParameter(5L);
Map<String, JobParameter> map= new HashMap<>();
map.put(jobName,jb);
ApplicationContext context = new ClassPathXmlApplicationContext("quartz-context.xml");
JobLauncher launcher=(JobLauncher) context.getBean("jobLauncher");
JobLocator locator= (JobLocator) context.getBean("jobRegistry");
setJobLauncher(launcher);
setJobLocator(locator);
setJobName("helloWorldJob");
// TODO Auto-generated method stub
JobExecution result = null;
try {
result = jobLauncher.run(jobLocator.getJob(jobName), new JobParameters(map));
} catch (JobExecutionAlreadyRunningException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JobRestartException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JobInstanceAlreadyCompleteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JobParametersInvalidException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchJobException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("ExamResult Job completetion details : "+result.toString());
}
here in setJobName method i am hard coding my spring batch job name ,
But in my project we are having nearly 800 jobs, so acc to approarch we need to make 800 wrapper classes.
Please help me , that how to resolve this solution by making generic class.
I sincerely hope you aren't really using that class, it will eventually eat all your memory as you are recreating your application over and over.
Spring already has support for quartz and especially the construction of jobs in the form of the SpringBeanJobFactory which you can use to your advantage especially if you extend it with some auto wiring capabilities.
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private ApplicationContext context;
#Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object object = super.createJobInstance(bundle);
context.getAutowireCapableBeanFactory().autowireBean(object);
return object;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.context=applicationContext;
}
}
Then rewrite your job class as something like this
public class SpringBatchJob implements Job {
private final Logger logger = LoggerFactory.getLogger(SpringBatchJob.class);
private String jobName;
#Autowired
private JobLocator jobLocator;
#Autowired
private JobLauncher jobLauncher;
#Override
public void execute(JobExecutionContext context) throws org.quartz.JobExecutionException {
JobDataMap JobDataMap = context.getMergedJobDataMap();
JobParametersBuilder builder = new JobParametersBuilder();
for (Map.Entry<String, Object) param : jobDataMap.entrySet()) {
String key = param.getKey();
Object val = param.getValue();
builder.addString(key, String.valueOf(val)); // Or make it smarter by doing type detection.
}
Job jobToLaunch = jobLocator.getJob(jobName);
JobExecution result;
try {
result = jobLauncher.run(jobToLaunch, builder.to);
} catch (JobExecutionException e) {
throw new org.quartz.JobExecutionException("Exception execution job '"+this.jobName+"'", e);
} finally {
logger.info("{} Job completetion details ", this.jobName, result);
}
}
}
Now you need to configure the SchedulerFactoryBean to use the AutowiringSpringBeanJobFactory by setting the jobFactory property. When you done then you just need to configure the quartz jobs appropriately.
For the sample you posted the following will launch the helloWorldJob when it is triggered to launch.
public static void main(String[] args) {
try {
ApplicationContext context = new ClassPathXmlApplicationContext("quartz-context.xml");
JobLauncher launcher=(JobLauncher) context.getBean("jobLauncher");
JobLocator locator= (JobLocator) context.getBean("jobRegistry");
Scheduler schedulerFactoryBean=(Scheduler) context.getBean("quartzSchedulerFactoryBean");
JobDetail job = newJob(SpringBatchJob.class)
.withIdentity("myJob001", "group1")
.usingJobData("jobName", "helloWorldJob")
.build();
Trigger trigger1 =newTrigger().withIdentity("myTrigger001", "group1")
.startNow()
.withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever())
.build();
schedulerFactoryBean.scheduleJob(job, trigger1);
schedulerFactoryBean.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
Notice the .usingJobData("jobName", "helloWorldJob"), the SpringBeanJobFactory will try to satisfy all setter methods on the SpringBatchJob class. This has a setJobName which will get injected with helloWorldJob when launched. The functionality is extended by the AutowiringSpringBeanJobFactory to also auto wire the needed infrastructure beans from Spring Batch.
If you need to pass additional properties to the Spring Batch job (like keys to use or other information, just add another usingJobData("your-property", your-value). The modified SpringBatchJob will map all quarts job parameters to Spring Batch parameters before launching the job.
Note: This was typed from the top of my head, I haven't actually tested this, but it should at least give you an idea on how to do this.
I am using Quartz CronScheduler to execute a job every 15 minutes. Every time the job executes it checks the DB for any change in the cron expression and updates the job scheduler for the next run. I have implemented the above in the following way:
#Service
public class QuartzSchedulerService {
private static final Logger LOG = LoggerFactory.getLogger(QuartzSchedulerService.class);
private Scheduler scheduler;
#PostConstruct
private void init() {
try {
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
} catch (Exception e) {
LOG.error("Unable to start quartz scheduler", e);
}
}
#PreDestroy
private void destroy() {
try {
scheduler.shutdown();
} catch (Exception e) {
LOG.error("Unable to shutdown quartz scheduler", e);
}
}
public void registerCronJob(Class<? extends Job> jobClass, String cronExpression) {
try {
String jobName = jobClass.getSimpleName();
CronScheduleBuilder cronBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName).build();
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName).withSchedule(cronBuilder).build();
scheduler.scheduleJob(jobDetail, cronTrigger);
LOG.info("Registered Cron Job:" + jobName + " " + jobDetail.getKey());
} catch (Exception e) {
LOG.error("Unable to register cron job", e);
}
}
public void updateCronSchedule(Class<? extends Job> jobClass, String cronExpression) {
try {
String jobName = jobClass.getSimpleName();
CronScheduleBuilder cronBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger newCronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName).withSchedule(cronBuilder).build();
scheduler.rescheduleJob(TriggerKey.triggerKey(jobName), newCronTrigger);
LOG.info("Updated Cron Job:" + jobName + " " + newCronTrigger.getJobKey());
LOG.info("Jobs executed: " + scheduler.getMetaData().getNumberOfJobsExecuted());
} catch (Exception e) {
LOG.error("Unable to reschedule cron job", e);
}
}
}
The class which implements the Job interface is as belows:
#Component
#DisallowConcurrentExecution
public class PropertiesReloadJob implements Job {
private static final Logger LOG = LoggerFactory.getLogger(PropertiesReloadJob.class);
#Autowired
private QuartzSchedulerService schedulerService;
#Autowired
private PropertiesService propertiesService;
public void loadAtStartup() {
load();
LOG.info("--- Registerting PropertiesReload Cron Job ---");
schedulerService.registerCronJob(PropertiesReloadJob.class, propertiesService.getCacheReloadCronExpression());
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
load();
LOG.info("--- Updating Pro Cron Job ---");
schedulerService.updateCronSchedule(PropertiesReloadJob.class, propertiesService.getCacheReloadCronExpression());
}
public void load(){
// Load properties from DB
}
The loadAtStartup() method is called during context initializtion and then after every 15 minutes the execute() method is called.
The cron expression used is: 0 0/15 * 1/1 * ? *
Now, the problem is as follows:
Lets say that the job starts at 3:00:00, it will execute as many times it can till 3:00:01, rather than executing only once.
Next the job will start at 3:15:00 and again will run as many times it can till 3:15:01.
The number of times the job executes is different every time.
I am not sure what is causing this behaviour. I have tested the cron expression with cronmaker.
Can somebody point out the error here ?
public static void setupSchedule() {
try {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
JobDetail job = newJob(Reader.class).withIdentity("job1", "group1").build();
String Frequency = Props.getProps().getProperty("BIRTHDAYFREQUENCY");
CronTrigger ct = newTrigger().withIdentity("trigger1", "group1")
.withSchedule(cronSchedule(Frequency)).build();
scheduler.scheduleJob(job, ct);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
If you are asking to implement quartz scheduler in web application then answer is yes.
All you have to do put all scheduler configuration in servlet init method. Like you have done it your question. Init method will be called only once on start-up of application or on first request. So all the configuration and scheduler time will be set at that time. Make sure to include all the quartz dependencies.
private Scheduler scheduler ;
public void init(ServletConfig config) throws ServletException
{
JobKey jobKeyA = new JobKey("jobA", "group1");
JobDetail jobA = JobBuilder.newJob(CallJob.class)
.withIdentity(jobKeyA).build();
//jobA.getJobDataMap().put("queue_setup", queue_setup);
Trigger trigger1 = TriggerBuilder
.newTrigger()
.withIdentity("triggerJobA", "group1")
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(1).repeatForever()).build();
//runs every minute
scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(jobA, trigger1);
}
Job class
public class CallJob implements Job {
#Override
public void execute(JobExecutionContext arg0) throws JobExecutionException
{
System.out.println("Yes job is running");
}
}