I'm using Quartz 1.8 to write some code that runs a job on a daily/weekly/monthly basis. When that job runs it should create a nested job. For some reason though, neither the nested JobDetail nor Trigger wind up with entries in the database, nor do they run.
Here's the example I'm working with:
public class QuartzSSCCE {
private static Logger LOG = Logger.getLogger(QuartzSSCCE.class);
private static long counter = 0L;
private static Scheduler scheduler;
public void scheduleOuterJob(){
try{
LOG.info("About to try to schedule OuterJob");
CronTrigger ct = new CronTrigger("OuterJobTrigger" + counter++, "OuterJobGroup", "30 * * ? * *");
ct.setStartTime((new DateTime(new Date())).plusSeconds(3).toDate());
DateTime endTime = new DateTime(new Date());
endTime = endTime.plusMinutes(5);
ct.setEndTime(endTime.toDate());
JobDetail jd = new JobDetail("OuterJobDetail" + counter++, "OuterJobGroup", OuterJob.class);
scheduler.scheduleJob(jd, ct);
} catch (Exception e){
LOG.fatal("something went wrong while scheduling the outer job", e);
}
}
public static class OuterJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try{
LOG.info("running OuterJob");
//Trigger trigger = TriggerUtils.makeImmediateTrigger("InnerTriggerName" + counter++, 1, 1);
SimpleTrigger simpleTrigger = new SimpleTrigger(
"InnerTriggerName" + counter++,
"InnerTriggerGroup",
(new DateTime(new Date())).plusSeconds(10).toDate(),
(new DateTime(new Date()).plusSeconds(50)).toDate(),
1,
1000
);
JobDetail jd = new JobDetail("InnerJobDetail" + counter++, "InnerJobGroup", InnerJob.class);
scheduler.scheduleJob(jd, simpleTrigger);
} catch (Exception e){
LOG.fatal("something went wrong while scheduling the inner job", e);
}
}
}
public static class InnerJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
LOG.info("InnerJob is running. The time at the beep is: " + new Date());
}
}
public void setScheduler(Scheduler scheduler) {
QuartzSSCCE.scheduler = scheduler;
}
}
This class obtains an Scheduler instance from a SchedulerFactoryBean. Elsewhere in my code I instantiate an instance of QuartzSSCCE like so:
QuartzSSCCE quartzSSCCE = new QuartzSSCCE();
quartzSSCCE.scheduleOuterJob();
I wind up seeing entries in the log for "About to try to schedule OuterJob" and "running OuterJob" but it appears that the InnerJob never gets run. I've attempted this with both a trigger returned from the call to TriggerUtils.makeImmediateTrigger() as well as a SimpleTrigger.
Why won't my InnerJob run?
First of all, my English is poor!
Quartz use reflection to create job instance, as your code show:
JobDetail jd = new JobDetail("InnerJobDetail" + counter++, "InnerJobGroup", InnerJob.class);
But nested class can't create instance directly by reflection, so the InnerJob is not fired.
Related
I am trying to set date and time from database in Quartz Schedular but is unable to do so. Please help me out.
Here is my code:
public class CroneScheduler {
public CroneScheduler() throws Exception {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sche = sf.getScheduler();
sche.start();
JobDetail jDetail;
jDetail = new JobDetail("Newsletter", "NJob", MyJob.class);
//"0 0 12 * * ?" Fire at 12pm (noon) every day
//"0/2 * * * * ?" Fire at every 2 seconds every day
CronTrigger crTrigger = new CronTrigger("cronTrigger", "NJob", "0/2 * * * * ?");
sche.scheduleJob(jDetail, crTrigger);
}
}
If the version of quartz is 1.7.2,then you can use below code:
public void resetJob(String expression){
ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
Scheduler scheduler = (Scheduler) applicationContext.getBean("testScheduler");
try {
CronTriggerBean trigger = new CronTriggerBean();
trigger.setCronExpression(expression);
trigger.setName("testJobTrigger");
trigger.setGroup(Scheduler.DEFAULT_GROUP);
trigger.setJobName("testJobDetail");
scheduler.rescheduleJob("testJobTrigger", Scheduler.DEFAULT_GROUP, trigger);
} catch (SchedulerException | ParseException e) {
e.printStackTrace();
}
}
If the version of quartz is newer than 1.7.2,you can use below code:
public void resetJob(String expression){
ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
Scheduler scheduler = (Scheduler) applicationContext.getBean("testScheduler");
CronTriggerImpl trigger = null;
try {
TriggerKey triggerKeys = TriggerKey.triggerKey("testJobTrigger",Scheduler.DEFAULT_GROUP);
trigger = new CronTriggerImpl();
trigger.setCronExpression(expression);
trigger.setKey(triggerKeys);//keep key the same
scheduler.rescheduleJob(triggerKeys,trigger);
} catch (ParseException | SchedulerException e) {
e.printStackTrace();
}
}
I am adding a job to quartz scheduler. After that I call the attached debug print jobs function. It does not list the job. Is the function call to getCurrentlyExecutingJobs() maybe limited to return max. of 10 jobs?
public void scheduleManagementEmail(ManagementEmailConfig managementEmailConfig, Scheduler scheduler) throws SchedulerException
{
logger.debug("Scheduling Management Email " +
managementEmailConfig.getManagementEmailConfigId());
String jobKey = "SendManagementEmailJob_" +
managementEmailConfig.getManagementEmailConfigId();
Class<? extends Job> jobClass = SendManagementEmailJob.class;
JobDetail job = JobBuilder.newJob(jobClass).withIdentity(new JobKey(jobKey)).build();
Trigger trigger = sendManagementEmailJob.getTriggerWithSchedule(managementEmailConfig);
trigger.getJobDataMap().put("managementEmailConfigId", managementEmailConfig.getManagementEmailConfigId());
if (!scheduler.checkExists(new JobKey(jobKey)))
{
scheduler.scheduleJob(job, trigger);
}
debugPrintJobs();
}
public void debugPrintJobs() {
try {
logger.debug("Quartz Jobs");
Scheduler s_scheduler = this.getJobScheduler();
List<JobExecutionContext> currentJobs = s_scheduler.getCurrentlyExecutingJobs();
for (JobExecutionContext jobCtx : currentJobs) {
JobKey jobKey = jobCtx.getJobDetail().getKey();
JobDetail jobDetail = s_scheduler.getJobDetail(jobKey);
List<? extends Trigger> triggers = s_scheduler.getTriggersOfJob(jobKey);
Date nextFireTime = null;
if (triggers.size() > 0)
{
nextFireTime = triggers.get(0).getNextFireTime();
}
logger.debug("Name= "+ jobKey.getName() + " Group=" + jobKey.getGroup() + " NextFireTime=" + nextFireTime);
}
} catch (Exception e) {
logger.debug("debugPrintJobs:" + e.getMessage());
}
The method getCurrentlyExecutingJobs() will return only the jobs that are running, not every scheduled job.
To get every scheduled job, you should do something like this:
Scheduler scheduler = getScheduler();
try {
// All scheduled jobs
for (String groupName : scheduler.getJobGroupNames()) {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
final List<? extends Trigger> triggersOfJob = scheduler.getTriggersOfJob(jobKey);
// Do something with the info you just got
// ...
}
}
} catch (SchedulerException e) {
log.error("Retrieving jobs", e);
}
I am scheduling a task as:
ScheduledExecutorService dataService = Executors.newScheduledThreadPool(1);
Future<?> dataTimerHandle = dataService.scheduleAtFixedRate(runnable, 100, freq, TimeUnit.MILLISECONDS);
This works fine without a flaw.
However, when a certain flag becomes true on user action, the task is no more required periodically, and needs to be executed just once. I then attempt cancelling the task and submitting it just once as follows:
if(!dynamicUpdate) {
dataTimerHandle.cancel(true);
dataTimerHandle = dataService.submit(runnable);
}
else { //Reschedule again:
dataTimerHandle = dataService.scheduleAtFixedRate(runnable, 100, freq, TimeUnit.MILLISECONDS);
}
But seems like the runnable is still executing periodically and cancel() is not working as expected.
Is there an alternate strategy for this?
The problem is probably not in the Future's cancel() method. Here is a small runnable example that appears to be doing exactly what you want:
import java.util.concurrent.*;
public class CancelPeriodicTask {
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduler = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
scheduler.setRemoveOnCancelPolicy(true);
try {
new CancelPeriodicTask().test(scheduler);
} catch (Exception e) {
e.printStackTrace();
} finally {
int openTasks = scheduler.shutdownNow().size();
println("Finished, open tasks: " + openTasks);
// openTasks will be 1 when RemoveOnCancelPolicy is false
// and the executor is closed within the scheduled task-period.
}
}
private static long sleepTime = 25L;
public void test(ScheduledThreadPoolExecutor scheduler) throws Exception {
// sleep 5 times at scheduled interval
SleepTask sleepTask;
ScheduledFuture<?> scheduledSleep = scheduler.scheduleAtFixedRate(sleepTask = new SleepTask(), 0, 2 * sleepTime, TimeUnit.MILLISECONDS);
sleepTask.sleepTimes.await();
println("Cancelling scheduledSleep. Done: " + scheduledSleep.isDone() + ", cancelled: " + scheduledSleep.isCancelled());
scheduledSleep.cancel(true);
Thread.sleep(2 * sleepTime);
println("Running sleepTask once.");
scheduler.submit(sleepTask);
Thread.sleep(2 * sleepTime);
scheduledSleep = scheduler.scheduleAtFixedRate(sleepTask, 0, 2 * sleepTime, TimeUnit.MILLISECONDS);
println("Re-scheduled scheduledSleep. Done: " + scheduledSleep.isDone() + ", cancelled: " + scheduledSleep.isCancelled());
Thread.sleep(5 * sleepTime);
println("Cancelling scheduledSleep. Done: " + scheduledSleep.isDone() + ", cancelled: " + scheduledSleep.isCancelled());
scheduledSleep.cancel(true);
}
class SleepTask implements Runnable {
public final CountDownLatch sleepTimes = new CountDownLatch(5);
public int sleepCount;
#Override public void run() {
println("Sleeping " + (++sleepCount));
try { Thread.sleep(sleepTime); } catch (Exception e) {
e.printStackTrace();
}
sleepTimes.countDown();
}
}
private static final long START_TIME = System.currentTimeMillis();
private static void println(String msg) {
System.out.println((System.currentTimeMillis() - START_TIME) + "\t " + msg);
}
}
This is expected since you are sending the cancel command to the wrong handle. When you call service.submit() it returns a handle for the newly created future, and you can't use the very same handle to send cancel messages to future's created via other calls
Obviously you can shut down the executor service via sevice.shutdown() to not start any runnable submitted after a certain moment
I think, future.cancel method interrupts the thread the RUNNING thread, so you would need to catch the InterruptedException in the runnable class & just return;
I'm using Cron to schedule an the upload of a file to the server in specific time given by the adminstrator. i created an interface on java, where the user can choose the time of execution of the upload program, and submit the chosen values, once submitted the following method is executed:
public class Reminder {
String minute;
//static int i=0;
String heur;
String substr=",";
String patterns;
List<String> list = null;
List<String> lines = new ArrayList<>();
Timer timer;
FTPUploadFileDemo up=new FTPUploadFileDemo();
public void start() throws IOException {
/************ Get the chosen values from the administrator saved in a CSV file *********************************************************/
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader("C:/Users/BACKENDPC1/Desktop/timer.csv"));
String line = null;
while ((line = reader.readLine()) != null) {
lines.add(line);
}} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();}
/**********************create cron patterns *********************************************/
patterns="";
for(int i=0; i<lines.size();i++) {
heur=lines.get(i).substring(0, lines.get(i).indexOf(substr));
minute=lines.get(i).substring(lines.get(i).indexOf(substr) + substr.length());
System.out.println("Time selected is: "+heur+","+minute);
patterns=patterns+minute+" "+heur+" * * *|";
}
System.out.println(patterns);
// Creates the scheduler.
Scheduler scheduler = new Scheduler();
// Schedules the task, once every minute.
scheduler.schedule(patterns,new RemindTask());
scheduler.start();
try {
Thread.sleep(1L * 60L * 1000L);
} catch (InterruptedException e) {
System.out.println(e);
}
// Stops the scheduler.
scheduler.stop();
}
class RemindTask extends TimerTask {
public void run() {
up.Uplaod();
}
}
}
the scheduling works and it runs but, every time the user interface i created freeze, i don't get any error and the program keeps running but the i can't use the interface anymore. can any one help me please.
public void start() throws IOException {
..............
try {
Thread.sleep(1L * 60L * 1000L);
} catch (InterruptedException e) {
System.out.println(e);
}
...............
}
Why you pause main thread for 60 secounds? Scheduler run his own tasks in separate thread, so you shouldn't interrupt execution of main thread.
ALSO, try to put breakpoints and debug your program step by step and localize problem
And don't write math operations like this:
1L * 60L * 1000L
will be enough to write:
1L * 60 * 1000
In addition, every time format your code:
In Eclipse: Ctrl + Shift + F
In IntelliJ IDEA: Ctrl + Alt + L
I am trying to do something conceptually simple...
We have multiple portlets loading on a Dashboard. I need to measure the load time that each takes. I have implemented a simple StopWatch class, and need to run multiple instance of it simultaneously, for each portlet, while the Dashboard is loading.
So the parameters supplied will be:
The portlet name
The element to be checked, indicating a successful load.
Here is the StopWatch class:
public class StopWatch implements Runnable {
private long startTime;
private long stopTime;
private String tElement;
private String tPortletName;
public StopWatch(String portletName,String element) {
tElement = element;
tPortletName = portletName;
}
public void start() {
startTime = System.currentTimeMillis();
}
public void stop() {
stopTime = System.currentTimeMillis();
}
public long getTime() {
return stopTime - startTime;
}
#Override
public void run() {
selenium.selectFrame(tPortletName);
StopWatch sw = new StopWatch();
sw.start();
while (selenium.isElementPresent(tElement)==false)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
sw.stop();
long time = sw.getTime();
System.out.println(tPortletName+" load time="+time);
}
}
In the calling program,
StopWatch sw1 = new StopWatch(portlet1,element1);
StopWatch sw2 = new StopWatch(portlet2,element2);
ExecutorService threadExecutor = Executors.newFixedThreadPool(3);
threadExecutor.execute(sw1); // start task1
threadExecutor.execute(sw2); // start task2
Upon running this, I get the following exception:
com.thoughtworks.selenium.SeleniumException: ERROR Server Exception: commandHolder got filled during execution of doCommandWithoutWaitingForAReponse
Any clues on what causes this?
Most likely the reason is that you are sending commands faster then Selenium can process them.
Anyway this approach should not work since DefaulSelenium and other Selenium classes are not synchronized so if you most likely you will get deadlocks or unpredictable results.
I think you will have to test this in two steps: load dashboard, wait for first portlet, then reload dashboard and wait for second portlet. Do all of this in the main thread, something like:
private void waitForPortlet(String portletName, String element) {
long startTime = System.currentTimeMillis();
while (selenium.isElementPresent(element) == false)
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
long stopTime = System.currentTimeMillis();
System.out.println(portletName + " load time=" + (stopTime - startTime));
}
And use:
waitForPortlet(name1, element1);
selenium.refresh();
waitForPortlet(name2, element2);