Scheduling task using Spring Scheduler - java

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...
}
}

Related

JAVA: Run the cron job task even schedule has come

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());
}

How to specify PST time zone in #Scheduled annotation that should trigger every hour between 7AM PST to 6 PM PST?

My Java Web application has a Cron Job Scheduler which should trigger every hour starting from 7AM PST to 6PM PST. I am not getting how to specify PST time zone using zone parameter inside #Scheduled annotation. Kindly help
#Component
public class CronJobForFailedLoans {
#Scheduled(cron ="0 0 7-18 ? * *")
public void cronJobForFailedLoans() {
// Perform operations
} }
Your cron expression is valid just use Zone to specify the timezone, use online cron for validating and generating cron expression
#Scheduled(cron ="0 0 7-18 ? * *", zone="America/Los_Angeles")

Spring scheduled fixedRateString as Duration

The #Scheduled documentation here states that the fixedRateString value can be the delay in milliseconds as a String value, e.g. a placeholder or a java.time.Duration compliant value. Meaning I can either write
#Scheduled(fixedRateString = "45s")
OR
#Scheduled(fixedRateString = "45000")
And it should be the same. However when I try to run it I get
Encountered invalid #Scheduled method 'updateWarmupInstances': Invalid fixedRateString value "45s" - cannot parse into long
So it this a mistake on Spring's part or am I doing something wrong
?
To use the method #Scheduled(fixedRateString) for durations, you could use a String with the standard duration:
#Scheduled(fixedRateString = "PT45S")
The prefix PT is for ISO-8601 standard and in this example, it's mean the duration of 45 seconds.
Another example could be a duration of 1h:
#Scheduled(fixedRateString = "PT1H")
You are looking at the return value of the method, not the input. The input can only be a String in milliseconds, but the return value is a value compliant with Duration.

Quartz: setting cron expression to run on the 1st and Last day of month

Quartz documentation gives an example for running a cron job on the last day of every month, like this:
0 15 10 L * ?
Fire at 10:15am on the last day of every month
However, I'd like to run a cron job on the 1st AND Last day of the month.
I would expect the cron would look somthing like this:
0 15 10 1,L * ?
But this syntax is not valid by quartz.
I couldn't find any proper/similar example in their tutorial. Any suggestions?
So after some digging in quartz code I found this:
// throw an exception if L is used with other days of the month
if(exprOn == DAY_OF_MONTH && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) {
throw new ParseException("Support for specifying 'L' and 'LW' with other days of the month is not implemented", -1);
}
org.quartz.CronExpression (quartz 2.2.2).
It seems 'L' is not supported for day-of-month with other days of the month. Too bad it's not anywhere in their documentation :(

Cron Expression is not working for last day of the month

I want to schedule a task to run on last day of every month at 10:10 AM.
The cron expression is 0 10 10 L * ?
Now the problem is CronSequenceGenerator is throwing NumberFormatException for 'L' value. This means Spring's CronSequenceGenerator doesn't support this kind of expression. But if I am passing only passing numeric it is working fine.
Here is the full stacktrace:
Exception in thread "main" java.lang.NumberFormatException: For input string: "L"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.valueOf(Integer.java:582)
at org.springframework.scheduling.support.CronSequenceGenerator.getRange(CronSequenceGenerator.java:324)
at org.springframework.scheduling.support.CronSequenceGenerator.setNumberHits(CronSequenceGenerator.java:297)
at org.springframework.scheduling.support.CronSequenceGenerator.setDays(CronSequenceGenerator.java:275)
at org.springframework.scheduling.support.CronSequenceGenerator.setDaysOfMonth(CronSequenceGenerator.java:266)
at org.springframework.scheduling.support.CronSequenceGenerator.parse(CronSequenceGenerator.java:239)
at org.springframework.scheduling.support.CronSequenceGenerator.<init>(CronSequenceGenerator.java:81)
at org.springframework.scheduling.support.CronTrigger.<init>(CronTrigger.java:54)
at org.springframework.scheduling.support.CronTrigger.<init>(CronTrigger.java:44)
at com.hcdc.coedp.datantar.scheduler.SchedulerUtil.start(SchedulerUtil.java:75)
at com.hcdc.coedp.datantar.scheduler.SchedulerUtil.changeTrigger(SchedulerUtil.java:106)
at com.hcdc.coedp.datantar.scheduler.SchedulingService.scheduleTransfer(SchedulingService.java:70)
at com.hcdc.coedp.datantar.scheduler.Scheduler.schedule(Scheduler.java:107)
at main.Main.main(Main.java:47)
Update for Spring 5.3
Spring now supports the following syntax to run on the last day of the month
#Scheduled(cron = "0 0 0 L * *") // last day of the month at midnight
Original answer:
This Schedule runs on the last day of the month an 10:10AM:
#Scheduled(cron = "0 10 10 28-31 * ?")
public void doStuffOnLastDayOfMonth() {
final Calendar c = Calendar.getInstance();
if (c.get(Calendar.DATE) == c.getActualMaximum(Calendar.DATE)) {
// do your stuff
}
}
Please check this link
Cron Maker
Give your expression in the text box
0 10 10 L * ?
The last day of the month is not supported by Spring. See CronSequenceGenerator's javadoc.
There is another possible approach, depending on what you want to do:
import org.apache.commons.lang3.time.DateUtils;
#Scheduled(cron = "0 0 0 1 * ?") // runs on the first day of each month
public void doStuffOnFirstDayOfMonth() {
Date now = DateUtils.addDays(new Date(), -1); // "now" is now on the last day of the month
}
I use this to generate statistics for a month of data. The routine should run on the first day of the next month to be sure to capture all data of the full previous month.
While this does not answer the question in the sense of having a Cron Expression for the last day of the month, it still can be a solution for jobs which need to run for a full month and this as soon as possible after the month has come to an end.
Expression syntactically correct with your condition: 0 10 10 L 1/1 ? *
And this is workaround that you could be interested: Workaround for CronSequenceGenerator Last day of month?

Categories