I'm using Quartz to write a simple server monitor in Java:
public class ServerMonitorJob implements Job {
#Override
public void execute(JobExecutionContext ctx) {
// Omitted here for brevity, but uses HttpClient to connect
// to a server and examine the response's status code.
}
}
public class ServerMonitorApp {
private ServerMonitorJob job;
public ServerMonitorApp(ServerMonitorJob jb) {
super();
this.job = jb;
}
public static void main(String[] args) {
ServerMonitorApp app = new ServerMonitorApp(new ServerMonitorJob());
app.configAndRun();
}
public void configAndRun() {
// I simply want the ServerMonitorJob to kick off once
// every 15 minutes, and can't figure out how to configure
// Quartz to do this...
// My initial attempt...
SchedulerFactory fact = new org.quartz.impl.StdSchedulerFactory();
Scheduler scheduler = fact.getScheduler();
scheduler.start();
CronTigger cronTrigger = new CronTriggerImpl();
JobDetail detail = new Job(job.getClass()); // ???
scheduler.schedule(detail, cronTrigger);
scheduler.shutdown();
}
}
I think I'm somewhere around the 70% mark; I just need help connecting the dots to get me all the way there. Thanks in advance!
You are almost there:
JobBuilder job = newJob(ServerMonitorJob.class);
TriggerBuilder trigger = newTrigger()
.withSchedule(
simpleSchedule()
.withIntervalInMinutes(15)
);
scheduler.scheduleJob(job.build(), trigger.build());
Check out the documentation, note that you don't need a CRON trigger when you simply want to run the job every 15 minutes.
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");
}
}
}
I tried to find it, but without results. I'd like to have object having path to bash script and cron expression specifying when to run it. It's SpringBoot project. I see it like this:
public class TestScript {
private String cronExpression;
private String pathToFile;
public void execute() {
// either it's #Scheduled or execute another way
}
}
Is it possible to do? Please guide me even a little if you can.
Ok, I managed to make my custom service that dynamically creates jobs:
#Service
public class DynamicJob {
public void schedule(TestScript testScript) {
try {
JobDetail job = JobBuilder.newJob(TestScript.class)
.withIdentity(testScript.getName(), "default group")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(testScript.getName().concat(" trigger"), "groupAll")
.withSchedule(CronScheduleBuilder.cronSchedule(testScript.getCronExpression()))
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
} catch (Exception e) {
e.printStackTrace();
}
}
}
TestScript class implements org.quartz.Job and I use quartz library version 2.2.1
Using Timer and TimerTask.
Not able to understand why is this configuration starting the task immediately on deployment (using this in a web based Spring app). It should be started at today.getTime and then must repeat every day.
Calendar today = Calendar.getInstance();
today.set(Calendar.HOUR_OF_DAY, 3);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
MyTask task = new MyTask();
Timer timerJob = new Timer();
timerJob.schedule(task, today.getTime(),
TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));
I think, it would be better to use CronTrigger or Trigger with 24hours repeat interval.
Example of CronTrigger:
public class CronTriggerRunner {
public static void main(String args[]) throws SchedulerException, Exception {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
JobDetail job = JobBuilder.newJob(ClassToRun.class).withIdentity("jobName", "group").build();
// Starting CronTrigger
String exp = "0 0 9 * * ?"; //trigger format, everyday at 9:00 am
Trigger trigger = TriggerBuilder.newTrigger()
.startNow()
.withSchedule(
CronScheduleBuilder.cronSchedule(exp))
.build();
// Planning job detail
scheduler.scheduleJob(job, trigger);
// starting scheduler
scheduler.start();
}
}
ClassToRun.java
public class ClassToRun implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try{
//doSomething
}
catch(Exception e){
e.printStackTrace(System.out);
}
}
}
Everyday at 9:00 am, public void execute() function will doSomething :D
Hope this will help. Please let me know.
EDIT: You need to download and add 2 jar files. 1) quartz-2.2.1.jar 2) slf4j-api-1.6.6.jar
I am running a simple quartz job in main class which runs every 30 secs.
public class Start {
public static void main(String[] args) throws Exception {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job = newJob(MyJob.class).withIdentity("myJob","XXX").build();
Trigger trigger = TriggerBuilder.newTrigger()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(30)
.repeatForever())
.build();
sched.scheduleJob(job, trigger);
sched.start();
}
}
Here i am implementing InterruptableJob like
public class MyJob implements InterruptableJob {
private volatile boolean isJobInterrupted = false;
private JobKey jobKey = null;
private volatile Thread thisThread;
public MyJob() {
}
#Override
public void interrupt() throws UnableToInterruptJobException {
// TODO Auto-generated method stub
System.err.println("calling interrupt:"+thisThread+"==>"+jobKey);
isJobInterrupted = true;
if (thisThread != null) {
// this call causes the ClosedByInterruptException to happen
thisThread.interrupt();
}
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
thisThread = Thread.currentThread();
jobKey = context.getJobDetail().getKey();
System.err.println("calling execute:"+thisThread+"==>"+jobKey);
}
}
Now i tried to stop the job using another main class like in every possible way with no luck
public class Stop {
public static void main(String[] args) throws Exception {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
// get a "nice round" time a few seconds in the future...
Date startTime = nextGivenSecondDate(null, 1);
JobDetail job = newJob(MyJob.class).withIdentity("myJob", "XXX").build();
Trigger trigger = TriggerBuilder.newTrigger()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(30)
.repeatForever())
.build();
sched.scheduleJob(job, trigger);
sched.start();
try {
// if you want to see the job to finish successfully, sleep for about 40 seconds
Thread.sleep(60000) ;
// tell the scheduler to interrupt our job
sched.interrupt(job.getKey());
Thread.sleep(3 * 1000L);
} catch (Exception e) {
e.printStackTrace();
}
System.err.println("------- Shutting Down --------");
TriggerKey tk=TriggerKey.triggerKey("myJob","group1");
System.err.println("tk"+tk+":"+job.getKey());
sched.unscheduleJob(tk);
sched.interrupt(job.getKey());
sched.interrupt("myJob");
sched.deleteJob(job.getKey());
sched.shutdown();
System.err.println("------- Shutting Down ");
sched.shutdown(false);
System.err.println("------- Shutdown Complete ");
System.err.println("------- Shutdown Complete ");
}
}
Can anyone please tell me the correct way to stop the job? Thanks a lot.
This question seems to answer the exact problem you're describing:
You need to write a your job as an implementation of InterruptableJob. To interrupt this job, you need handle to Scheduler, and call interrupt(jobKey<<job name & job group>>)
As-per the InterruptableJob documentation:
The interface to be implemented by Jobs that provide a mechanism for having their execution interrupted. It is NOT a requirement for jobs to implement this interface - in fact, for most people, none of their jobs will.
Interrupting a Job is very analogous in concept and challenge to normal interruption of a Thread in Java.
The means of actually interrupting the Job must be implemented within the Job itself (the interrupt() method of this interface is simply a means for the scheduler to inform the Job that a request has been made for it to be interrupted). The mechanism that your jobs use to interrupt themselves might vary between implementations. However the principle idea in any implementation should be to have the body of the job's execute(..) periodically check some flag to see if an interruption has been requested, and if the flag is set, somehow abort the performance of the rest of the job's work.
Emphasis mine. It is analogous but not the same. You're not expected to use Threads (but indeed you could if that's what your Job does...).
An example of interrupting a job can be found in the java source for the class org.quartz.examples.DumbInterruptableJob. It is legal to use some combination of wait() and notify() synchronization within interrupt() and execute(..) in order to have the interrupt() method block until the execute(..) signals that it has noticed the set flag.
So I recommend reading the documentation and inspecting examples in the full download.
Edit: I am using quartz-2.1.5.jar. Here's the summary of my classes:
HttpPollingJob extends PollingJob extends ScheduledJob implements org.quartz.Job
Specifically:
1) ScheduledJob implements Quartz Job (abstract base class for all my Job types):
import org.quartz.Job;
import org.quartz.Trigger;
public abstract class ScheduledJob implements Job {
private Trigger trigger;
public ScheduledJob() {
this(null);
}
public ScheduledJob(Trigger trig) {
super();
if(trig == null)
trig = getDefaultTrigger();
setTrigger(trig);
}
public Trigger getTrigger() {
return trigger;
}
public void setTrigger(final Trigger trig) {
trigger = trig;
}
protected abstract Trigger getDefaultTrigger();
}
2) PollingJob extends ScheduledJob - all "pollers" poll some resource/endpoint with a specific frequency:
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import com.me.jobs.ScheduledJob;
public abstract class PollingJob extends ScheduledJob {
private static long DEF_FREQUENCY = 10 * 1000; // 10 secs
private String name;
private long frequency;
public PollingJob(final String nm) {
this(nm, DEF_FREQUENCY);
}
public PollingJob(final String nm, final long freq) {
super();
setName(nm);
setFrequency(freq);
}
public abstract void poll(JobExecutionContext context);
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
poll(context);
}
public String getName() {
return name;
}
public void setName(final String nm) {
name = nm;
}
public long getFrequency() {
return frequency;
}
public void setFrequency(final long freq) {
frequency = freq;
}
protected final Trigger getDefaultTrigger() {
TriggerBuilder<?> triggerBuilder = TriggerBuilder.newTrigger()
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(DEF_FREQUENCY));
return triggerBuilder.build();
}
}
3) HttpPollingJob extends PollingJob - "HTTP pollers" poll a web server (using HTtpClient):
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.quartz.JobExecutionContext;
import com.me.MonitoredEvent;
import com.me.MonitoredEventRegistrar;
public class HttpPollingJob extends PollingJob {
private String serverURL;
private org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(HttpPollingJob.class);
public HttpPollingJob(final String nm, final String server) {
super(nm);
setServerURL(server);
}
public String getServerURL() {
return serverURL;
}
public void setServerURL(final String server) {
serverURL = server;
}
#Override
public final void poll(JobExecutionContext context) {
MonitoredEvent event = null;
try {
// This is where we would use HttpClient to connect to a web server and poll it.
System.out.println("Job fired!");
}
catch(Throwable thrown) {
logger.error(thrown.getMessage());
}
}
}
4) JobDriver - defines several HttpPollingJobs and uses Quartz to start them:
public class JobDriver {
private List<HttpPollingJob> jobs;
public JobDriver() {
HttpPollingJob job1 = new HttpPollingJob("job-1", "http://www.example.com/1");
HttpPollingJob job2 = new HttpPollingJob("job-2", "http://www.example.com/2");
HttpPollingJob job3 = new HttpPollingJob("job-3", "http://www.example.com/3");
jobs = new ArrayList<HttpPollingJob>();
jobs.add(job1);
jobs.add(job2);
jobs.add(job3);
}
public static void main(String[] args) {
JobDriver driver = new JobDriver();
driver.startJobs();
}
private void startJobs() {
try {
// Obtain a basic SchedulerFactory and fire it up.
SchedulerFactory schedulerFactory = new org.quartz.impl.StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// Define a job for every declared monitor.
JobBuilder jobBuilder = null;
for(ScheduledJob job : jobs) {
Trigger trigger = job.getTrigger();
jobBuilder = JobBuilder.newJob(job.getClass());
// Bind the current job to this trigger.
scheduler.scheduleJob(jobBuilder.build(), trigger);
// TODO: Shut the scheduler down politely?!?!
}
catch(Throwable exc) {
logger.error(exc.getMessage());
// Force application to kick out.
throw new RuntimeException(exc);
}
}
}
When I run this code I get a perfect startup with no errors or runtime exceptions. If I sprinkle System.out.println statements I can see every single line of code executing flawlessly. The only problem is, once the program is running, its not printing the "Job fired!" message indicating that the polling job is kicking off.
I've tried every combination of start() and shutdown() I can think of to no avail. Can any Quartz mavens look at this code and tell me why the job isn't firing?
In the logs (I configured log4j) I see the Quartz worker thread being created for the scheduled job. I feel like I'm 99% of the way there but am just missing something obvious. Thanks in advance!
#4herpsand7derpsago yes you are right, you are 99% there, I ran your code and there is only one problem in it, the Default constructors are absent in HttpPollingJob and PollingJob classes, For that reason Scheduler is not able to create their instances,
Simple Solution add following code in below classes
HttpPollingJob class
public HttpPollingJob() {
}
PollingJob class
public PollingJob() {
}
Bingo, the following messages will be printed
Job fired!
Job fired!
Job fired!
If you want to repeat the trigger, add following code in PollingJob
protected final Trigger getDefaultTrigger() {
TriggerBuilder<?> triggerBuilder = TriggerBuilder
.newTrigger()
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(DEF_FREQUENCY).repeatForever());
return triggerBuilder.build();
}
Hoping that now I will receive the bounty :)
BONUS
Seems like you want to poll or do something with urls, A better way to pass that using king JobDataMap
Updated JobDriver
import java.util.ArrayList;
import java.util.List;
import org.quartz.JobBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
public class JobDriver {
private List<HttpPollingJob> jobs;
public JobDriver() {
HttpPollingJob job1 = new HttpPollingJob("job-1",
"http://www.example.com/1");
HttpPollingJob job2 = new HttpPollingJob("job-2",
"http://www.example.com/2");
HttpPollingJob job3 = new HttpPollingJob("job-3",
"http://www.example.com/3");
jobs = new ArrayList<HttpPollingJob>();
jobs.add(job1);
jobs.add(job2);
jobs.add(job3);
}
public static void main(String[] args) {
JobDriver driver = new JobDriver();
driver.startJobs();
}
private void startJobs() {
try {
// Obtain a basic SchedulerFactory and fire it up.
SchedulerFactory schedulerFactory = new org.quartz.impl.StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// Define a job for every declared monitor.
JobBuilder jobBuilder = null;
for (HttpPollingJob job : jobs) {
Trigger trigger = job.getTrigger();
jobBuilder = JobBuilder.newJob(job.getClass());
jobBuilder.usingJobData("name", job.getName());
jobBuilder.usingJobData("url", job.getServerURL());
// Bind the current job to this trigger.
scheduler.scheduleJob(jobBuilder.build(), trigger);
// TODO: Shut the scheduler down politely?!?!
}
} catch (Throwable exc) {
// Force application to kick out.
throw new RuntimeException(exc);
}
}
}
updated HttpPollingJob
import java.util.Map;
import org.quartz.JobExecutionContext;
public class HttpPollingJob extends PollingJob {
private String serverURL;
private org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(HttpPollingJob.class);
public HttpPollingJob(final String nm, final String server) {
super(nm);
setServerURL(server);
}
public HttpPollingJob() {
}
public String getServerURL() {
return serverURL;
}
public void setServerURL(final String server) {
serverURL = server;
}
#Override
public final void poll(JobExecutionContext context) {
try {
Map dataMap = context.getJobDetail().getJobDataMap();
String nm = (String)dataMap.get("name");
String url = (String)dataMap.get("url");
// This is where we would use HttpClient to connect to a web server and poll it.
System.out.println("Job fired! name:"+nm+" url:"+url);
}
catch(Throwable thrown) {
logger.error(thrown.getMessage());
}
}
}
new output
Job fired! name:job-1 url:http://www.example.com/1
Job fired! name:job-2 url:http://www.example.com/2
Job fired! name:job-3 url:http://www.example.com/3
Apparently, you have not started the trigger. See Quartz Tutorial or Javadocs:
// Trigger the job to run now, and then every 40 seconds
Trigger trigger = newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build();
Its your constructors - the JobBuilder looks for the no-args and since they're not defined it refuses to build the jobs. Add empty no-arg ctors and you're all set.
Could you try to change the code of the method getDefaultTrigger in the class PollingJob into the following :
protected final Trigger getDefaultTrigger() {
return TriggerBuilder.newTrigger()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(DEF_FREQUENCY))
.startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
.build();
}
i feel some issue with the way you create the trigger.
Remember you cannot reuse trigger for multiple jobs
Try creating trigger with unique identity and group like below
Trigger everyHourTrigger = newTrigger().withIdentity("everyWeeklyTrigger", "group1")
.startNow().withSchedule(cronSchedule("0 1 * * * ?")).build();