I am trying to schedule a quartz job according to the following plan:
Job runs daily and should only be executed between 9:30am and 6:00pm. I am trying to achieve this via DailyCalendar. Here what my DailyCalendar looks like:
DailyCalendar dCal = new DailyCalendar(startTimeString, endTimeString);
dCal.setTimeZone(TimeZone.getDefault());
dCal.setInvertTimeRange(true);
where start and end time strings are of the format HH:MM
Next, I try to schedule this job:
Scheduler myscheduler = StdSchedulerFactory.getDefaultScheduler();
SimpleTrigger trigger = new SimpleTrigger();
myscheduler.addCalendar("todcal", cal, true, true);
trigger.setName("TRIGGER " + alertName);
trigger.setJobName(alertName);
trigger.setJobGroup(alertName);
trigger.setCalendarName("todcal");
logger.info("Adding TOD job");
myscheduler.scheduleJob(trigger); // line causing exception
myscheduler.start();
As soon as scheduleJob is called I see the following Exception:
Based on configured schedule, the given trigger will never fire.
The configuration seems fine to me but I cant find any sample code for using DailyCalendar so I could be wrong here. Please help
You don't seem to be setting a repeat count or repeat interval on your trigger. So it will only fire once at the current moment (because you did not set a future start time), which probably happens to be during the calendar's exclusion time - which is why it would be calculated that it will never fire.
Job runs daily and should only be
executed between 9:30am and 6:00pm.
How often should the job be executed within that timeframe? Once? Once an hour? Every 10 seconds?
You need to define the repeat interval for your trigger. Look at setRepeatInterval(long repeatInterval) method of SimpleTrigger. It defines in milliseconds the interval with which the trigger will repeat.
Related
i have spring boot and java application. at particular time of the day it should execute a method. so in the production server we have kept 4 dyno's and because of 4 dyno's it is executing 4 times per day. so i have used cache and getting the date . based on the date i try to execute the method only once .still it is executing 4 times.
#Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.cron.job}")
public void processScheduled() {
synchronized(this) {
LocalDate localDate = redisTemplate.getValue("DATE");
if (localDate == null || LocalDate.now().isAfter(localDate)) {
log.info("Entered process in SchedulerConfig");
redisTemplate.putValue("DATE", LocalDate.now());
schedulerService.processScheduled();
}
}
}
the above code is written in a config java class.
the schedulerService.processScheduled(); should be triggered only once a day irrespective of no of the dyno's.
can anyone help me on this ?
I am assuming you are using Heroku Dynos, so there are 4 separate instances of your app running in production. Since there are 4 separate instances, your use of synchronized will be of little use here. All 4 of your instances are getting invoked at the same time, so there is a chance that, all of them will get the value of redisTemplate.getValue("DATE") as not null. You need an atomic operation with an centralized entity. Redis does serve as an centralized entity, but redisTemplate.getValue("DATE") and then redisTemplate.putValue("DATE", LocalDate.now()) is not an atomic operation. So it is very possible that 4 instances call redisTemplate.getValue("DATE") and get the real date. Since all 4 of them are not null, they will all update the value and then process your operation.
You should try using redisTemplate.delete(key). It is an atomic operation which returns true if the key is deleted else returns false. So your code may look like this.
#Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.cron.job}")
public void processScheduled() {
boolean isDeleted= redisTemplate.delete("DATE"); // only one will get true, other will get false.
if (isDeleted) {
log.info("Entered process in SchedulerConfig");
schedulerService.processScheduled();
// sleep for some time and then update the date value
redisTemplate.putValue("DATE", LocalDate.now());
}
}
Or you can update the Date value after some time of the invocation with #Scheduled
#Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.flag.update.job}")
public void updateDateFlag() {
redisTemplate.putValue("DATE", LocalDate.now());
}
I have a requirement where user can set a end date or can set a specific number of occurrences before stopping any job.
As for example,
Consider I have to send sms to a specific number and that should start from now and the sms will be sent in each 5 minutes.
Now based on user's choice the above job will be stopped on a specific time or after n number of occurrences.
And I am using cron scheduler of quartz.
Now stopping it at a specific date time is easy and I have done it like following way;
trigger = TriggerBuilder.newTrigger()
.startAt(startDateObj)
.endAt(endDate)
.withIdentity(uniqueID, "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule(cronString)
)
.build();
But what to do if I have to stop it after n number of occurrences? I know it can be done with simple schedule like;
simpleSchedule().withRepeatCount(1).withIntervalInSeconds(15)
But how to do the same for cron scheduler? For some reasons I can not shift to any other type of schedule except cron.
Any help will be great for me.
Please let me know if any more data is required.
Thanks in advance.
You can count the endDate using computeEndTimeToAllowParticularNumberOfFirings() method. (That name though!).
See the following example:
CronTrigger trigger = new Trigger()
.withIentity("some_id")
.withSchedule(buildCronScheduler("some_cron_exp"))
.build();
Date endDate = TriggerUtils.computeEndTimeToAllowParticularNumberOfFirings(
(OperableTrigger) trigger,
new BaseCalendar(Calendar.getInstance().getTimeZone()),
repeatCount);
trigger = trigger.getTriggerBuilder().endAt(endDate).build();
I am using Quartz library to add cron timer to my application.
Sample usage is explained here, specifying run periodicity in this API is done thru so-called "cron string" (cron expression) - it is well-explained in examples here and in official docs here.
CronTrigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(cronSchedule("0/20 * * * * ?")) // cron string
.build();
I understand how to run a task specifying starting point + periodicity (say, at 11am every day, every Friday, etc).
But I need to run it every day at 11am, 12am, 3pm, 7pm etc - I can just enumerate exact times. How can I specify that? I need same task (job) be executed every day exactly at these many times.
It is stupid to create so many Trigger(s), each with separate cron expression. Is there a nice solution?
Here, docs say:
, - used to specify additional values. For example, “MON,WED,FRI” in
the day-of-week field means “the days Monday, Wednesday, and Friday”.
So maybe this works: "0 0 11am,12am,3pm,7pm * * ?" ?
P.S. Or all I can do is to create a separate Trigger for every hour and then add all such Triggers (with same job) to Scheduler like
myScheduler.scheduleJob(sameJob, trigger11am);
myScheduler.scheduleJob(sameJob, trigger12am);
myScheduler.scheduleJob(sameJob, trigger3pm);
myScheduler.scheduleJob(sameJob, trigger7pm);
Yes, this is the way it can be done:
// setup CronTrigger
// misfire policies (when app was down at scheduled time):
// https://www.nurkiewicz.com/2012/04/quartz-scheduler-misfire-instructions.html
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("triggerName", "myGroupName")
.withSchedule(
// at 11:30am, 12:30am, 03:30pm, 06:30pm, etc every day, including Sunday, Monday, days-off
CronScheduleBuilder.cronSchedule("0 30 11,12,15,18,21,23 * * ?")
// don't run missed jobs (missed when app was down)
.withMisfireHandlingInstructionDoNothing())
.build();
Here official examples at the bottom confirm it - see "Fire at 2:10pm and at 2:44pm every Wednesday".
I'm developing a website with Spring and Hibernate (the website is about stock trading).
At about 12 AM everyday, I need to cancel all orders. Currently my solution is using a scheduled task that runs every hour:
<task:scheduled ref="ordersController" method="timeoutCancelAllOrders" fixed-delay="60*60*1000" />
Then in the method timeoutCancelAllOrders, I get the current time and check, if it's between 11PM and 12AM then do the task
The way I see it, task schedule starts when I start the Server ( I'm using Tomcat in Eclipse), but when I deploy it on an online hosting ( I'm using Openshift), I have no idea when is the starting time of task schedule.
My question is:
1: How to do it more automatic ? Is there anything like myTask.startAt(12AM) ?
2: I'm living in Vietnam but the server (Openshift) is located in US, so here's how I do the check :
Date currentTime = new Date();
DateFormat vnTime = new SimpleDateFormat("hh:mm:ss MM/dd/yyyy ");
vnTime.setTimeZone(TimeZone.getTimeZone("Asia/Ho_Chi_Minh"));
String vietnamCurrentTime = vnTime.format(currentTime);
String currentHourInVietnam = vietnamCurrentTime.substring(0, 2);
System.out.println(currentHourInVietnam);
if(currentHourInVietnam.equals("00")){
// DO MY TASK HERE
}
That looks stupid. How can I improve my code ?
Use a CRON specification:
<task:scheduled ref="beanC" method="methodC" cron="0 0 0 * * ?"/>
Run at midnight every day.
If you instead annotate your method, you can specify the time zone:
#Scheduled(cron="0 0 0 * * ?", zone="Asia/Ho_Chi_Minh")
public void methodC() {
// code
}
I am trying to build a Trigger in Quartz Scheduler API which should get executed with following criteria.
Start on particular date (Jan 25, 2012)
Start at predefined time (08.00.00 AM)
Every Week.
Can be scheduled for alternate week or every 3 week (if not every week)
On these particular days of week (Monday,Tuesday,Friday etc)
I have created the following expression
newTrigger().withIdentity(cronTriggerDTO.getTiggerId(), "simpleGroup")
.startAt(getTriggerExecutionDate(cronTriggerDTO))
.withSchedule(calendarIntervalSchedule().withIntervalInWeeks
(cronTriggerDTO.getWeeklyInterval())).build();
but I am confused how I should add the condition to execute this trigger on particular days of week
I'd use CronScheduleBuilder.cronSchedule(String cronExpression), like this:
newTrigger().withIdentity(cronTriggerDTO.getTiggerId(), "simpleGroup")
.startAt(getTriggerExecutionDate(cronTriggerDTO))
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 * * 1,2,5"))
.build();
Use DailyTimeIntervalScheduleBuilder
Set daysOfWeek = new HashSet();
daysOfWeek.add(1);
daysOfWeek.add(2);
daysOfWeek.add(5);
newTrigger().withIdentity(cronTriggerDTO.getTiggerId(), "simpleGroup")
.startAt(getTriggerExecutionDate(cronTriggerDTO))
.withSchedule(dailyTimeIntervalSchedule()
.onDaysOfTheWeek(daysOfWeek)
.startingDailyAt(new TimeOfDay(8,0)))
.build();
Use cron trigger and below is the simple way to prepare cron expression
int second = 53;//prepare from the time selected from UI(fire time)
int minute=0;
int hour=8;
String dayOfWeek="1,3";//prepare it from the days you get from UI(give check box values as 1 for SUN,....)
String cronExpression = String.format("%d %d %d ? * %s",second,minute , hour, dayOfWeek);
newTrigger()
.withIdentity(cronTriggerDTO.getTiggerId(), "simpleGroup")//
.withSchedule(cronSchedule(cronExpression)//
.startAt(getTriggerExecutionDate(cronTriggerDTO))
.build();
Then schedule the job..,hope this helps you.