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.
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");
}
}
}
My aim is to create a queue system where I can specify a maximum amount of concurrent jobs for each group, i.e. for group A maximum 3 jobs should run at the same time, for group B max Y jobs etc. The jobs can be executed both on cron schedule and only once with SimpleTrigger, therefor I can't check the queue when scheduling the job, I have to check it before or during execution. I'm implementing a joblistener and I'm trying to prevent execution in the jobToBeExecuted() method. I've tried scheduler.interrupt() but it doesn't work when the job hasn't started yet. scheduler.deletejob() and scheduler.unschedule() didn't stop it from executing either.
Any ideas?
public class JobQueueListener implements JobListener {
#Override
public void jobToBeExecuted(JobExecutionContext context) {
JobKey currentJobKey = context.getJobDetail().getKey();
JobDetail jobDetail = context.getJobDetail();
Scheduler scheduler = context.getScheduler();
if (shouldBePutInQueue(currentJobKey)) {
/// Prevent execution and put in queue here, but how?
}
}
#Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
//Check queue and execute next in queue
}
}
Can you look at TriggerListener
You should implement TriggerListener and have your abort logic within "vetoJobExecution" method.
boolean vetoJobExecution(Trigger trigger,
JobExecutionContext context)
Its Called by the Scheduler when a Trigger has fired, and it's associated JobDetail is about to be executed. If the implementation vetos the execution (via returning true), the job's execute method will not be called.
I am new to java and trying to learn quartz. I have main method
public static void main(String[] args) throws SchedulerException {
try {
JobDetail job1 = JobBuilder.newJob(Job1.class).withIdentity("job1", "group1").build();
Trigger trigger1 = TriggerBuilder.newTrigger().withIdentity("cronTrigger1", "group1")
.withSchedule(CronScheduleBuilder.weeklyOnDayAndHourAndMinute(3, 12, 38)).build();
Scheduler scheduler1 = new StdSchedulerFactory().getScheduler();
scheduler1.start();
scheduler1.scheduleJob(job1, trigger1);
scheduler1.shutdown();
}
catch (Exception e) {
e.printStackTrace();
}
Which works fine. It prints to the console on 3rd day of the week at 12:38 pm.
Now, what I want to do is to reschedule the trigger, so that it deletes the previous stored trigger and creates a new trigger with new schedule.
I read a lot of things at a lot of places but I just can't seem to understand clearly what I actually have to do, for ex:
public void execute(JobExecutionContext context) throws JobExecutionException {
Trigger newTigger = what ever you want;
Trigger oldTrigger = context.getTrigger()
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.rescheduleJob(oldTrigger.getKey(), newTrigger);
}
and also this:
// Define a new Trigger
Trigger trigger = newTrigger()
.withIdentity("newTrigger", "group1")
.startNow()
.build();
// tell the scheduler to remove the old trigger with the given key, and
// put the new one in its place
sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger);
but I can't understand the approach(I do understand what is happening in the code though). Thanks in advance.
My goal is to schedule a recurrent job that happens on a non-even rate. I am going to migrate from first snippet to the second:
1st:
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == MSG1) {
//recurrent job here
long nextTime = nextTime();
sendMessageAtTime(obtainMessage(MSG1), nextTime);
}
}
}
};
2nd:
ScheduledExecutorService mExecutor;
while (true){
mExecutor.schedule(new Callable() {
public Object call() throws Exception {
long startTime = SystemClock.uptimeMillis();
//recurrent job here
delay = nextTime() - startTime ;
return true;
}
}, delay, TimeUnit.MILLISECONDS);
}
My questions are:
1- is it true in the first snippet that the thread, to which the mHandler is referring, is free between jobs to do other tasks or handle other messages?
2- However in the second snippet, Thread is always busy doing the loop. right?
3- How can I rewrite the second code so that I won't loose thread activity between jobs (in delays)?
Any help is highly appreciated
Your second code won't work as expected. After the first task has been scheduled and is waiting to be executed, the while loop continues to schedule more tasks, all of them with the same delay. So you'll end up having thousands, probably millions of tasks. And of course, because the main thread is running an infinite loop without any wait, it is busy all the time. This is probably not what you want.
You should better use a simliar approach than the handler uses above:
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.schedule(() -> {
// do work
// reschedule
executor.schedule(this, nextTime() - System.currentTimeMillis());
}, delay, TimeUnit.MILLISECONDS);
(Of course you should also check that the delay you specify when rescheduling is not negative).
Update: If you need to process the result of each execution individually, another approach similar to your second code example is possibly what you want. It schedules the task executions insisde a loop and hands over the result to a Consumer, as soon as it is available. (Note the future.get() inside the loop which causes the looping thread to pause until the task is done).
public static <T> void schedule(ScheduledExecutorService scheduler,
Schedule schedule, Callable<T> task, Consumer<? super T> consumer)
throws InterruptedException, ExecutionException {
while (true) {
if (Thread.interrupted()) throw new InterruptedException();
long delay = schedule.nextTime() - System.currentTimeMillis();
if (delay < 0) continue; // skip this step
ScheduledFuture<? extends T> future = scheduler.schedule(task,
delay, schedule.getUnit());
consumer.accept(future.get());
}
}
Also note the interruption check, so that other threads can stop execution by interrupting the looping thread. This simplifies the usage of this method inside another task in case you want to run it on a background thread too.
Schedule could be a functional interface that provides access to the scheduling information:
#FunctionalInterface
public interface Schedule {
long nextTime();
default TimeUnit getUnit() { return TimeUnit.MILLISECONDS; }
}
Btw.: The android.os.Handler is a very nice way to do what you want in android. So you should only migrate to ScheduledExecutorService if you really need its features (e.g. getting a Future result).
public class RecurrentJobThatHappensOnANonEvenRate {
/**
* Consider you have your job defined as below
*/
abstract class TheJob implements Runnable {
#Override
public void run() {
long startTime = System.currentTimeMillis();
doRecurrentJob();
schedule(nextTime() - startTime);
}
void doRecurrentJob() {
// Do the job
}
long nextTime() {
// calculate next execution time
long randomDelay = Math.round(5000 + Math.random() * 5000);
return System.currentTimeMillis() + randomDelay;
}
public abstract void schedule(long delay);
};
/**
* Example using `ScheduledExecutorService`.
*/
public void exampleWithScheduledExecutorService() {
TheJob theJob = new TheJob() {
private final ScheduledExecutorService executor =
Executors.newScheduledThreadPool(1);
#Override
public void schedule(long delay) {
executor.schedule(this, delay, TimeUnit.MILLISECONDS);
}
};
theJob.schedule(1500);
}
/**
* Example with `Handler` and using already existing `Thread` with
* `Looper` (most probably the main looper).
*/
public void exampleWithHandlerAndMainLooper() {
TheJob theJob = new TheJob() {
private final Handler handler =
// new Handler();
// or if you are not in the main thread:
new Handler(Looper.getMainLooper());
#Override
public void schedule(long delay) {
handler.postDelayed(this, delay);
}
};
theJob.schedule(1500);
}
/**
* Example with `Handler` and `HandlerThread` (a convenience thread
* class with looper).
*/
public void exampleWithHandlerAndHandlerThreadsLooper() {
TheJob theJob = new TheJob() {
private final HandlerThread handlerThread;
private final Handler handler;
private final long killThreadAt;
{
handlerThread = new HandlerThread("myThread");
// handler thread must be quit when you no longer use it.
// see nextTime() method below.
killThreadAt = System.currentTimeMillis() + 30000;
// alternatively you can set it to be a daemon thread.
// handlerThread.setDaemon(true);
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
}
#Override
public void schedule(long delay) {
handler.postDelayed(this, delay);
}
#Override
long nextTime() {
long nextTime = super.nextTime();
if(nextTime() > killThreadAt) {
handlerThread.quit();
}
return nextTime;
}
};
theJob.schedule(1500);
}
}
I had some similar issues .. I was trying to schedule different jobs at different rates and I found using the Quartz Scheduler library to handle all my scheduling problems a real relieve :)
For your problem: firing a job at a non-even rate, you could easily implement a TriggerListener and on completion reschedule the same job at nextTime()
The Quartz Scheduler easily integrates with Spring, Maven and has handles for all kind of scenarios like misfired jobs or thread exceptions.
Simple example (from the docs)
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
// define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
.withIdentity("job1", "group1")
.build();
// compute a time that is on the next round minute
int minutesInterval = nextTime();
// Trigger the job to run on the next round minute and repeat it forever
Trigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(
simpleSchedule()
.withIntervalInMinutes(minutesInterval)
.repeatForever()
)
.build();
// Tell quartz to schedule the job using our trigger
sched.scheduleJob(job, trigger);
sched.start();
I have an application with a few different, long running quartz jobs. Every job is triggered by a kind of event (for example user action) and it is intended to run only once per such an event. In the environment where the application works the following scenario happens...
Application is running,
Long running job is triggered,
During the execution of the job application shutdown occurs,
Application is starded again.
Is it possible to cause that quartz will automatically refire the job started and not finished previously (in the previous session of the application)? I mean using jdbc job store, which works well for misfired jobs - but is it possible to refire not finished job.
This is the best approach I've found:
Configure quartz scheduler with:
org.quartz.scheduler.interruptJobsOnShutdownWithWait=true
Make your recoverable jobs implementing InterruptableJob, and manually trigger the current job as part of interrupt logic (example below).
Write your own ShutdownHook to call Scheduler.shutdown(true) or use quartz ShutdownHookPlugin
This way, when an ordered shutdown is detected by the VM (hard shutdowns bust be handled by RequestRecovery: quartz jobDetail requestRecovery), jobs implementing InterruptableJob will be interrupted and re-triggered. This trigger will not occur until next start.
There is a quick example of how to implement:
public static class TriggerOnInterruptJob implements InterruptableJob {
private boolean interrupt = false;
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
LOGGER.debug("START");
synchronized (mutex) {
mutex.notifyAll();
}
executionCount.incrementAndGet();
try {
while (!interrupt)
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
context.getScheduler().triggerJob(context.getJobDetail().getKey());
} catch (SchedulerException e) {
e.printStackTrace();
}
}
#Override
public void interrupt() throws UnableToInterruptJobException {
interrupt = true;
}
}