JAVA: Run the cron job task even schedule has come - java

I already checked here but seems no solution given.
Here is my problem.
I have a cron job in my seam project which is written with jboss async. It runs at 3am everyday.
However last night, the application needed to reboot before that time. Past 3am when the application started.
The task set to run every 3am but did not run. In the code, the final expiration is set to 12/31/9999. Technically speaking, this will assume that it is already done.
Is there any chance to still run that job even past of scheduled given since it never run at that time? Like executing it right after the application is ready for production. If there are solutions, how would I make it?
Putting some flag to check if the job is done would be the least option.
Here is my sample code.
public void someMethodToSetJob() {
final String cronTabSchedule = "0 0 3 ? * MON-FRI *";
final Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 1);
cal.set(Calendar.SECOND, 0);
final Calendar expiry = Calendar.getInstance();
expiry.set(Calendar.MONTH, 11);
expiry.set(Calendar.DATE, 31);
expiry.set(Calendar.YEAR, 9999);
expiry.set(Calendar.SECOND, 0);
processBackgroundProcessCheck(cal.getTime(), cronTabSchedule, expiry.getTime());
}
#Asynchronous
#Transactional(TransactionPropagationType.REQUIRED)
public QuartzTriggerHandle processBackgroundProcessCheck(
#Expiration final Date when,
#IntervalCron final String cron,
#FinalExpiration final Date endDate) {
...
return null;
}
Any help would be highly appreciated. Thanks!

Use Spring batch tasklet to achieve that.. reason being, spring has provided ways to achieve last job run number/timing and picks next chunk from then on.
It would be far easier to achieve that way.
Some example you may find at this link.
https://www.mkyong.com/spring-batch/spring-batch-tasklet-example/
You might go for annotation based spring batch (If not comfortable with xml based)

It is possible by backdating the begin date which is #Expiration. Since I have in CRON schedule at 3AM, then let's say the application is deployed at 4AM. By setting the Date for #Expiration into something that it would catch the 3AM. it will run the process at the very moment. But the next schedule will be exactly 3AM.
public void someMethodToSetJob() {
final String cronTabSchedule = "0 0 3 ? * MON-FRI *";
final Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR_OF_DAY, 3);
cal.set(Calendar.SECOND, 0);
final Calendar expiry = Calendar.getInstance();
expiry.set(Calendar.MONTH, 11);
expiry.set(Calendar.DATE, 31);
expiry.set(Calendar.YEAR, 9999);
expiry.set(Calendar.SECOND, 0);
processBackgroundProcessCheck(cal.getTime(), cronTabSchedule, expiry.getTime());
}

Related

Quartz CronTrigger is not firing at the specified startAt() time

I have a scenario where I need to schedule a job which has to be execute daily at a specific time. When I schedule it with specific time as the start time for scheduler the quartz won't trigger the job at the set start time instead it would trigger at the next cycle i.e. after 24 hrs delay.Even on checking the the nextFireTime, we get a day's delay.
For E.g:
I need to schedule a job daily to run at 6 pm in the evening. And start it at 5 pm Today (27th March 2018).The job doesn't start and nextFireTime is 6pm 28th March 2018.
Code snippet :
Date startDateTime = new Date(scheduler.getStartDateTime());
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(startDateTime);
int hours = calendar.get(Calendar.HOUR_OF_DAY);
int minutes = calendar.get(Calendar.MINUTE);
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(scheduleTriggerName, schdeuleGroupName).startAt(startDateTime).withSchedule(dailyAtHourAndMinute(hours, minutes)).build();
JobDetail jobDetail = this.getJobDetail(schdeuleJobName, schdeuleGroupName);
Scheduler configuration for spring
SchedulerFactoryBean schedulerFactoryBean= new SchedulerFactoryBean();
QuartzAutowireBeanFactory jobFactory = new QuartzAutowireBeanFactory();
jobFactory.setApplicationContext(applicationContext);
schedulerFactoryBean.setJobFactory(jobFactory);
schedulerFactoryBean.scheduleJob(jobDetail, trigger)// scheduling the job
Solution
One liner:
Cron only handles 1-minute resolutions
The starttime that which was passed to the startAt() function was a timestamp till milliseconds and cron does support till minutes.
so the simple solution was to use the calendar to set the minutes and seconds as zero.
calendar.setTime(startDateTime);
calendar.set(Calendar.SECOND, 0); // this was the solution
calendar.set(Calendar.MILLISECOND, 0); // this was the solution
int hours = calendar.get(Calendar.HOUR_OF_DAY);
int minutes = calendar.get(Calendar.MINUTE);
trigger = TriggerBuilder.newTrigger();
trigger.startAt(calendar.getTime()).withSchedule(dailyAtHourAndMinute(hours, minutes));
Detailed One:
Finally I got the reason for the behavior, while debugging I saw that it was setting the delay of 24 hours but when one would print the time it would be in hh:mm:00 format I mean the output would set the seconds parts as 00 as default , so the problem was the starttime that was passed as parameter was a timestamp through the UI consisting of seconds and milliseconds so after reading on the Cron format I came to know that it supported till minutes resolutions so wherever it use to get the timestamp the startAt(startDateTime) in the
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(scheduleTriggerName, schdeuleGroupName).startAt(startDateTime).withSchedule(dailyAtHourAndMinute(hours, minutes)).build();
it would calculate the next run by skipping the seconds and milliseconds part.

Scheduling task using Spring Scheduler

I am using cron expression for the last working day of the month like this:
#Scheduled(cron = "0 0 8 LW * ?")
But after running this I got:
java.lang.IllegalStateException: Encountered invalid #Scheduled method 'fetchEmployeesDetailsAndSendNotification': For input string: "LW"
although the cron expression is valid.
Why am I getting this exception, and how can I fix it?
It would seem that your pattern is incorrect. The quartz scheduler format is not exactly the same as the Linux crontab format.
While quartz allows the definition of LW. The spring scheduler format (which you are using via the #Scheduled annotation) does not.
See the javadoc for Spring's CronSequenceGenerator which references the linux man page for the correct crontab patterns
The pattern is a list of six single space-separated fields: representing second, minute, hour, day, month, weekday. Month and weekday names can be given as the first three letters of the English names.
Try this:
#Scheduled(cron = "0 0 8 28-31 * ?")
public void yourMethod() {
Calendar calendar = Calendar.getInstance();
if (calendar.get(Calendar.DATE) == calendar.getActualMaximum(Calendar.DATE)) {
// do something...
}
}

What's the point of calendar.setTimeInMillis(System.currentTimeMillis()) right after instantiation?

In many posts and even on Google's site (here) I've seen this code :
// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
So I tested it in a standalone Java program (non Android) :
Calendar c = Calendar.getInstance();
System.out.println(new SimpleDateFormat("HH:mm:ss.SSS").format(new Date(System.currentTimeMillis())));
System.out.println(new SimpleDateFormat("HH:mm:ss.SSS").format(new Date(c.getTimeInMillis())));
Output :
01:23:33.884
01:23:33.876
It works fine without setting the time with setTimeInMillis explicitly.
What's the point of calendar.setTimeInMillis(System.currentTimeMillis()) ?
Is it erroneous, esp. in Android programming, to not set it this way ?

Simplest Method to Start AlarmManager With Time Value In Standard Format (ex 7:30)

I'd like to start my AlarmManager activity at a time specified by the user however the time string is stored in standard format (ex - 7:30) how can I use the AlarmManager to interact with a long value which is stored in standard format - instead of miliseconds as it usually is? Is it possible to do this without converting it into miliseconds? If so - how? If not - what is the 2nd best alternative? (I simply need to know the easiest way to wake an alarm if my time string is in standard format.)
SOURCE:
String time = 7:30
Intent intent2 = new Intent(New.this, Start.class);
PendingIntent pintent2 = PendingIntent.getActivity(Rules.this, 0, intent2,
0);
AlarmManager alarm2 = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm2.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
time != null ? 1000 : 0, pintent2);
EDIT:
I'm attempting to use the following method I found:
public Date getTimeFromTimeString(String time)
{
String[] splitStrings = time.split(":");
Date timeDate = new Date();
timeDate.setHours(Integer.parseInt(splitStrings[0]));
timeDate.setMinutes(Integer.parseInt(splitStrings[1]));
return timeDate;
}
However I'm getting warning stating:
The method setMinutes(int) from the type Date is deprecated
The method setSeconds(int) from the type Date is deprecated
Use a SimpleDateFormat to parse your String into a Calendar. Pull the milliseconds from there.
There is a source code for Calendar in this link https://code.google.com/p/ancal/source/checkout
It contains calendar with appointments, tasks, and also alarm. I don't know that if it will help you or not. But if you examine the codes, you can find the things that you want to do.
(You must create SVN for downloading this project)

How to get milliseconds from a date picker?

In my project I am saving milliseconds in a sqllite databse, by default I am saving
System.currentTimeMillis()
in the database, but there is an option for the user to select previous date from a date picker? But what sould I save then when user selects a previous or up comming days from the date picker? How can I get that day as a long(milliseconds) format?
Create a Calender instance and set the date you want. Then call calendar.getTimeInMillis();. See the answer of this previous SO question for more information.
EDIT To set the calendar date you can use something like this:
//Lets suppose you have a DatePicker instance called datePicker
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, datePicker.getDayOfMonth());
cal.set(Calendar.MONTH, datePicker.getMonth());
cal.set(Calendar.YEAR, datePicker.getYear());
See the Calendar class for more information.
I was looking for a similar solution for a javase scenario when I came across this answer. I made a little modification to Angelo's answer to make my own case work, and it gave me exactly what I was looking for. To make things a little more interesting, I created a method that can be reused.
class Controller {
public static Calendar cal = Calendar.getInstance();
public static long getEpoch_fromDatePicker( DatePicker datePicker ) {
Controller.cal.set(Calendar.DAY_OF_MONTH, datePicker.getValue().getDayOfMonth() );
Controller.cal.set(Calendar.MONTH, datePicker.getValue().getMonthValue() );
Controller.cal.set(Calendar.YEAR, datePicker.getValue().getYear() );
return Controller.cal.getTimeInMillis() /1000;
}
}
Someone might find this useful

Categories