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
}
Related
I need the job to be performed once a day during the week starting at 01:00 a.m. in the morning.
The application is packaged as a jar.
Running on windows as java -jar on the App it works normally by starting the job at the time reported in the CronTrigger.
Running on the linux server the application seems to loop in running every second.
Quartz Dependency Maven
<dependency>
<groupId>quartz</groupId>
<artifactId>quartz</artifactId>
<version>1.5.2</version>
</dependency>
**
This version is being used because the server runs java 1.4. The most current versions of quartz have generated errors while running the app**
I tried the cron expression to run once at 1 am from Monday to Friday. (0 0 1 ? * MON-FRI)
I tried every day at 00:00 (0 0 0 ? * * *)
Ref: cron generator https://www.freeformatter.com/cron-expression-generator-quartz.html
Class
package com.everis.centers;
import java.util.TimeZone;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import com.everis.centers.job.ExecuteJob;
public class ExportsApplication {
private static final String PERIOD = "0 0 1 ? * MON-FRI";
private static final String PERIOD_2 = "0 0 0 ? * * *";
public static void main(String[] args) {
try {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
JobDetail job = new JobDetail("exportJob", "vj1", ExecuteJob.class);
CronTrigger ct = new CronTrigger("exportTrigger", "vt1", PERIOD);
ct.setTimeZone(TimeZone.getTimeZone("America/Sao_Paulo"));
scheduler.scheduleJob(job, ct);
scheduler.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
If you use the expression cron (0 * / 2 *? * *) to run every 2 minutes a day. It works normal.
I do not understand the reason for the problem of not only performing once a day at 1am in the morning. If anyone can help, I've cleared all the documentation.
Obs
What I realized was, when the execution time is reached it gets executed in loop. That is, if I set to run 1 o'clock in the morning from that time it gets executed in loop. Instead of running once and waiting for the next day.
From here, you can understand the significance of each value in Cron expression. If you need to run a job at 12AM every day, try using this expression 0 0 0 * * * *. This will run job every 00:00 hour every day and only once. If you want to understand the importance of using ?, you can refer this answer here
Let me know if you face any issues.
You can try Crontab which use UNIX style of cron (no seconds support). If you need to specify seconds as well, you can refer this.
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".
Im trying to manage scheduled tasks using spring boot. I want to execute my job only one time at a particular date ( specified by the user ).
Here is my Job :
#Component
public class JobScheduler{
#Autowired
JobController controller;
// Retrieving the Date entered by the user
controller.getDateForExecution(); // 2016/05/24 10:00 for example
#Scheduled(???)
public void performJob() throws Exception {
controller.doSomething();
}
There are multiple options for Scheduled annotation such as fixedDelay, fixedRate, initialDelay, cron ... but none of these can accept a Date.
So, how can i execute my method at the specified Date dynamically ( ie depending on the Date insered ) ?
Ps : The method can be executed more than once if the user enter two or more Dates ..
Spring has the TaskScheduler abstraction that you can use: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-task-scheduler
It has a method to schedule execution of a Runnable at a certain Date:
ScheduledFuture schedule(Runnable task, Date startTime);
A little off-topic maybe: If JobController is a Spring Controller (or RestController), I would not autowire it into the JobScheduler. I would inverse it and inject the JobScheduler into the JobController.
Ok I know this is a very old questions but for future references, here's the answer:
You can use cron property, which gives much more control over the scheduling of a task. It lets us define the seconds, minutes ,and hours the task runs at but can go even further and specify even the years that a task will run in.
Below is a breakdown of the components that build a cron expression.
Seconds can have values 0-59 or the special characters , - * / .
Minutes can have values 0-59 or the special characters , - * / .
Hours can have values 0-59 or the special characters , - * / .
Day of month can have values 1-31 or the special characters , - * ? / L W C .
Month can have values 1-12, JAN-DEC or the special characters , - * / .
Day of week can have values 1-7, SUN-SAT or the special characters , - * ? / L C # .
Year can be empty, have values 1970-2099 or the special characters , - * / .
Just for some extra clarity, I have combined the breakdown into an expression consisting of the field labels.
#Scheduled(cron = "[Seconds] [Minutes] [Hours] [Day of month] [Month] [Day of week] [Year]")
For more you can follow this article: https://dzone.com/articles/running-on-time-with-springs-scheduled-tasks
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.
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.