I'm using quartz-scheduler 1.8.5. I've created a Job implementing StatefulJob. I schedule the job using a SimpleTrigger and StdSchedulerFactory.
It seems that I have to update the Trigger's JobDataMap in addition to the JobDetail's JobDataMap in order to change the JobDataMap from inside the Job. I'm trying to understand why it's necessary to update both? I noticed that the JobDataMap is set to dirty. Maybe I have to explicitly save it or something?
I'm thinking I'll have to dig into the source code of Quartz to really understand what is going on here, but I figured I'd be lazy and ask first. Thanks for any insight into the inner workings of JobDataMap!
Here's my job:
public class HelloJob implements StatefulJob {
public HelloJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException {
int count = context.getMergedJobDataMap().getInt("count");
int count2 = context.getJobDetail().getJobDataMap().getInt("count");
//int count3 = context.getTrigger().getJobDataMap().getInt("count");
System.err.println("HelloJob is executing. Count: '"+count+"', "+count2+"'");
//The count only gets updated if I updated both the Trigger and
// JobDetail DataMaps. If I only update the JobDetail, it doesn't persist.
context.getTrigger().getJobDataMap().put("count", count++);
context.getJobDetail().getJobDataMap().put("count", count++);
//This has no effect inside the job, but it works outside the job
try {
context.getScheduler().addJob(context.getJobDetail(), true);
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//These don't seem to persist between jobs
//context.put("count", count++);
//context.getMergedJobDataMap().put("count", count++);
}
}
Here's how I'm scheduling the job:
try {
// define the job and tie it to our HelloJob class
JobDetail job = new JobDetail(JOB_NAME, JOB_GROUP_NAME,
HelloJob.class);
job.getJobDataMap().put("count", 1);
// Trigger the job to run now, and every so often
Trigger trigger = new SimpleTrigger("myTrigger", "group1",
SimpleTrigger.REPEAT_INDEFINITELY, howOften);
// Tell quartz to schedule the job using our trigger
sched.scheduleJob(job, trigger);
return job;
} catch (SchedulerException e) {
throw e;
}
Update:
Seems that I have to put the value into the JobDetail's JobDataMap twice to get it to persist, this works:
public class HelloJob implements StatefulJob {
public HelloJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException {
int count = (Integer) context.getMergedJobDataMap().get("count");
System.err.println("HelloJob is executing. Count: '"+count+"', and is the job stateful? "+context.getJobDetail().isStateful());
context.getJobDetail().getJobDataMap().put("count", count++);
context.getJobDetail().getJobDataMap().put("count", count++);
}
}
This seems like a bug, maybe? Or maybe there's a step I'm missing to tell the JobDetail to flush the contents of its JobDataMap to the JobStore?
I think your problem is with using the postfix ++ operator - when you do:
context.getJobDetail().getJobDataMap().put("count", count++);
you're setting the value in the map to count and THEN incrementing count.
To me it looks like you wanted:
context.getJobDetail().getJobDataMap().put("count", ++count);
which would only need to be done once.
As you know, in Quartz, the trigger and the job are separate, rather than combined with some schedulers. They might be allowing you to add values to the datamap which are specific at the trigger level rather than the job level, etc.
I think it allows you to execute the same end job with a different set of data, but still have some common data at the job level.
As scpritch76 answered, the job and trigger are separate so that there can be many triggers (schedules) for a given job.
The job can have some base set of properties in the JobDataMap, and then the triggers can provide additional properties (or override base properties) for particular executions of the job in their JobDataMaps.
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
public class DynamicTestJob implements Job
{
private static final Logger log = LoggerFactory.getLogger(DynamicTestJob.class);
#Override
public void execute(final JobExecutionContext context)
{
final JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
Integer counter = (Integer) jobDataMap.get("counter");
if (counter == null)
{
counter = 1;
}
else
{
counter++;
}
jobDataMap.put("counter", counter);
System.out.println(counter);
}
}
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");
}
}
}
Every 5 minutes, 2 tasks run, one that updates, one that calculates.
The one that updates should always run first, but doesn't have to know anything about the calculator and visa versa.
Is there any way to manage this in a clean way without calling the other task from within.
After advice, this is my solution.
#PostConstruct
public void scheduleRunnableWithTrigger() {
logger.info("init scheduler");
scheduleTasks.schedule(() -> {
if(init.getIsInitialzed()) {
databaseUpdater.updatePrices();
for (ITechnicalAnalysis technicalAnalysis: adviser.getITechnicalAnalysis()) {
try {
CandleStick lastAddedCandleStickByCurrencyPair = candleStickService.getLatestByCurrencyPair(technicalAnalysis.getCurrencyPair());
technicalAnalysis.updateAlgorithms(lastAddedCandleStickByCurrencyPair);
logger.info(technicalAnalysis.getCurrencyPair() + " has candlesticks");
}catch (NullPointerException e) {
logger.warn(technicalAnalysis.getCurrencyPair() + " has no candlesticks");
}
}
adviser.calculateAnalyses();
}
}, periodicTrigger);
}
#Bean
public PeriodicTrigger periodicTrigger() {
PeriodicTrigger periodicTrigger = new PeriodicTrigger(TIME_TO_WAIT_FOR_DATABASE_TO_FILL, TimeUnit.MINUTES);
periodicTrigger.setInitialDelay(1);
return periodicTrigger;
}
According to the documentation. Be default there will be only one thread for scheduler.
So what you can do is you can schedule the tasks one after the other may be a second apart. This way second task will always run after first task.
Even if first task is not completed and schedule time for second task has reached, second task will have to wait for the thread from first task to be released.
You can also explicitly set the thread count for the scheduler with a bean declaration like this
#Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(THREAD_COUNT);// use 1 for this use case
return threadPoolTaskScheduler;
}
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 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.
I'm new to the #Schedule annotations in J2EE6
I want to run a job using EJB 3.x with Glassfish 3.1.
The javax.ejb.Schedule seems to be a good choice for us, so we could think of our custom time as something like:
#Singleton
public class CustomTimer {
#EJB
SettingsFacade settingsFacade;
#Schedule(second="someSecondParameter", minute="someMinuteParameter",hour="someHourParameter", persistent=false)
public void executeTimer(){
//Code executing something against database using the settingsFacade
}
}
Here, we want the parameters to be got from database, so they are changed every month. Any clean solution for this?
#Singleton
#Startup
public class ScheduleTimerService {
#Resource private TimerService timerService;
public void setTimerService(TimerService timerService) {this.timerService = timerService; }
#PostConstruct
private void postConstruct() {
timerService.createCalendarTimer(createSchedule());
}
#Timeout
public void timerTimeout(Timer timer) {
Add your code here to be called when scheduling is reached...
in this example: 01h:30m every day ;-)
}
private ScheduleExpression createSchedule(){
ScheduleExpression expression = new ScheduleExpression();
expression.dayOfWeek("Sun,Mon,Tue,Wed,Thu,Fri,Sat");
expression.hour("01");
expression.minute("30");
return expression;
}
}
No, there is no solution with #Schedule, because annotation attributes in general should be compile time constants.
When more flexibility is needed, programmatic timers can be used.
Also then polling database for changed configuration and removing existing and creating new timers must be implemented.
Well You need to created Two Scheduler
One Scheduler will run to update data from Database
Based On that You Can created Other Scheduler.
But for this Need to do it some what programmatic.
You also can see EJB Timers for the same what will help you in this case. which is also annotation based.
There is a simple way of doing this. I wanted to something that called a process every day but, the job itself should be done randomly over the same day. I managed to do that by adding a simple thread worker to run after the EJB timer service has been called. Then I would put it to sleep for a random amount of time during that day.
The following code is an example of a service that wakes up every 1 minute and waits for a thread to finish.
#Schedule(minute = "*/1", hour = "*", persistent = false)
public void runEveryMinute() throws InterruptedException {
log.log(Level.INFO, "Scheduling for every minute .. now it's: " + new Date().toString());
// Delay, in milliseconds before we interrupt adding a follower thread
//we can therefore garantee that it runs every day
long patience = 1000 * 5;
threadMessage("Starting forever alone no more thread");
long startTime = System.currentTimeMillis();
Thread t = new Thread(new MessageLoop());
t.start();
threadMessage("Waiting for new thread to finish");
// loop until MessageLoop thread exits
while (t.isAlive()) {
threadMessage("Still waiting...");
// Wait maximum of 1 second for MessageLoop thread to finish.
t.join(1000);
if (((System.currentTimeMillis() - startTime) > patience)
&& t.isAlive()) {
threadMessage("Tired of waiting! Adding new followers now!");
t.interrupt();
// Shouldn't be long now -- wait indefinitely
t.join();
}
}
threadMessage("Finally! You are not alone anymore!");
}
// Display a message, preceded by
// the name of the current thread
static void threadMessage(String message) {
String threadName = Thread.currentThread().getName();
System.out.format("%s: %s%n", threadName, message);
}
private static class MessageLoop implements Runnable {
public void run() {
String importantInfo[] = {
"A kid will eat ivy too"
};
try {
for (int i = 0;
i < importantInfo.length;
i++) {
// Pause for 4 seconds
int max = 10;
int min = 2;
int randomTimer = 0 + (int) (Math.random() * ((max - min) + 1));
Thread.sleep(randomTimer * 1000);
// Print a message
threadMessage(importantInfo[i]);
}
} catch (InterruptedException e) {
threadMessage("Patience is not a virtue! Thread stopping for now!");
}
}
}