Quartz: Cron expression that will never execute - spring

I know there is a duplicate here, which probably is exactly my case, though it would deserve some better explanation, which I will try to provide here.
I work with a Java web application using a Spring application context. In this context, I defined scheduled jobs using Quartz. These jobs are triggered by a cron defined in a .properties file.
The Spring context is embedded within the war, while the .properties file is on the application server (Tomcat in this particular case).
This is just fine and allows to define different crons according to the environment (development, integration, production, ...).
Now, when running this application locally on my own computer, I do not wish these jobs to be executed. Is there a way to write a cron expression which will never trigger?

TL;DR
In Quartz 1, you may use this cron: 59 59 23 31 12 ? 2099 (last valid date).
In Quartz 2, you may use this cron: 0 0 0 1 1 ? 2200
Using an expression far in the future
Made some quick tests using org.quartz.CronExpression.
String exp = "0 0 0 1 1 ? 3000";
boolean valid = CronExpression.isValidExpression(exp);
System.out.println(valid);
if (valid) {
CronExpression cronExpression = new CronExpression(exp);
System.out.println(cronExpression.getNextValidTimeAfter(new Date()));
}
When I do String exp = "# 0 0 0 1 1 ?";, the isValid test returns false.
With the sample given above yet, the output is the following:
true
null
Meaning:
the expression is valid;
there is no upcoming date which matches this expression.
For the scheduler to accept a cron trigger, though, the latter must match a date in the future.
I tried several years and figured out that once the year is above 2300, Quartz seems not to bother anymore (though I did not find a mention to a maximal value for the year in Quartz 2's documentation). There might be a cleaner way to do this, but this will satisfy my needs for now.
So, in the end, the cron I propose is 0 0 0 1 1 ? 2200.
Quartz 1 variant
Note that, in Quartz 1, 2099 is the last valid year. You can therefore adapt your cron expression to use Maciej Matys's suggestion: 59 59 23 31 12 ? 2099
Alternative: Using a date in the past
Arnaud Denoyelle suggested something more elegant, which my test above validates as a correct expression: instead of choosing a date in a far future, choose it in a far past:
0 0 0 1 1 ? 1970 (the first valid expression according to Quartz documentation).
This solution does not work though.
hippofluff highlighted that Quartz will detect an expression in past will never be executed again and therefore throw an exception.
org.quartz.SchedulerException: Based on configured schedule, the given trigger will never fire.
This seems to have been in Quartz for a long time.
Lessons learned: the test is not foolproof as is
This highlights a weakness of my test: in case you want to test a CronExpression, remember it has to have a nextValidTime1. Otherwise, the scheduler you will pass it to will simply reject it with the above mentioned exception.
I would advise adapting the test code as follows:
String exp = "0 0 0 1 1 ? 3000";
boolean valid = CronExpression.isValidExpression(exp);
if (valid) {
CronExpression cronExpression = new CronExpression(exp);
valid = cronExpression.getNextValidTimeAfter(new Date()) != null;
}
System.out.println("Can I use <" + exp + ">? " + (valid ? "Go ahead!" : "This shall fail."));
There you go: no need to think, just read the output.
1 This is the part I forgot when testing Arnaud's solution making me the fool and proving my test wasn't me-proof.

Technically, valid values for the optional Quartz year field are 1970-2099, so 2300 isn't an expected value. I'm assuming you really need to do this and your version of Quartz attempts to enforce valid cron syntax (day 1-31, month 1-12, and so on).
I'm currently using the following code in Resque-scheduler for Rails, which accepts schedule info in validated crontab format, to create a manual-run-only test job:
cron: "0 5 31 2 *"
The job will wait patiently for early morning February 31st before running. For an equivalent in Quartz crontrigger, try this line or some variant thereof:
0 0 5 31 2 ?

Give a try to this one: 59 59 23 31 12 ? 2099

If you're using the expression in a #Scheduled(cron="") expression (technically not using quartz, but rather common with spring those days) you can not use the 7-field year-in-the-future solution but those options:
If you're using spring 5.1+ (springBoot 2.1+) simply use "${your.cron.prop:-} and don't set the property to disable execution - see #Scheduled. Or set the property itself to "-" (make sure to use quotes if you're using a yml).
Disable the bean/service with the #Scheduled method altogether, for example by using a #ConditionalOnProperty("my.scheduleproperty.active") annotation and not setting the property (or setting it to false)

Hi you can try this it will never execute your schedular
just pass as - in cron
#Scheduled(cron = "${schedular.cron.expression}")
schedular.cron.expression=-

I found this whilst trying to solve a similar problem - disabling a cron expression - but ran into the same problems of requiring a valid future schedule date.
I also hit problems using the 7 value syntax - cannot specify a year in the cron schedule.
So I used this: 0 0 3 ? 2 MON#5
The next times this will execute are:
Monday, February 29, 2044 3:00 AM
Monday, February 29, 2072 3:00 AM
Monday, February 29, 2112 3:00 AM
Monday, February 29, 2140 3:00 AM
Monday, February 29, 2168 3:00 AM
So, essentially, to all intents and purposes, it's disabled. :)
Ah. Curses, this will only work for Quartz scheduler syntax - Spring CronTrigger syntax doesn't allow MON#5 for the fifth monday
So the next best thing is 0 0 3 29 2 ? which will only execute at 3am on the 29th Feb (leap years)

Now, when running this application locally on my own computer, I do not wish these jobs to be executed. Is there a way to write a cron expression which will never trigger?
If you want to disable scheduling on your computer, you have several ways to make that happen.
First you could move the configuration of Quartz to a #Profile-based configuration and not enable this profile locally. Quartz wouldn't start at all if the profile is not active.
An alternative is to configure Quartz to not start automatically. There is a SchedulerFactoryBean#setAutoStartup() that you can set in BeanPostProcessor registered in a dev profile. While this thread is quite old, Spring Boot offers an alternative by registering a SchedulerFactoryBeanCustomizer bean to do the same thing.

Use 31 for any month that has less days than this.
Thus, 0 0 31 2 * for February or
0 0 31 5 * for May
0 0 31 6 for June
* 0 0 31 9 * for September
0 0 31 11 * for November
should do to prevent the cron from execution.
These are valid cron expressions and can be validated on
https://crontab.guru/#0_0_31_2_*

Related

How can we schedule nifi data flow ? I'm using HDP 2.5

I want to schedule data flow in daily base through nifi.
For Example,
I need to run schedule on 9.00 AM in every morning.
Can anyone tell me what is procedure to make schedule data flow
There are three scheduling strategy available, see below details
Timer driven: This is the default mode. The Processor will be scheduled to run on a regular interval. The interval at which the Processor is run is defined by the ‘Run schedule’ option (see below).
Event driven: When this mode is selected, the Processor will be triggered to run by an event, and that event occurs when FlowFiles enter Connections feeding this Processor. This mode is currently considered experimental and is not supported by all Processors. When this mode is selected, the ‘Run schedule’ option is not configurable, as the Processor is not triggered to run periodically but as the result of an event. Additionally, this is the only mode for which the ‘Concurrent tasks’ option can be set to 0. In this case, the number of threads is limited only by the size of the Event-Driven Thread Pool that the administrator has configured.
CRON driven: When using the CRON driven scheduling mode, the Processor is scheduled to run periodically, similar to the Timer driven scheduling mode. However, the CRON driven mode provides significantly more flexibility at the expense of increasing the complexity of the configuration. The CRON driven scheduling value is a string of six required fields and one optional field, each separated by a space.
You typically specify values one of the following ways:
Number: Specify one or more valid value. You can enter more than one value using a comma-separated list.
Range: Specify a range using the - syntax.
Increment: Specify an increment using / syntax. For example, in the Minutes field, 0/15 indicates the minutes 0, 15, 30, and 45.
You should also be aware of several valid special characters:
* — Indicates that all values are valid for that field.
?  — Indicates that no specific value is specified. This special character is valid in the Days of Month and Days of Week field.
L  — You can append L to one of the Day of Week values, to specify the last occurrence of this day in the month. For example, 1L indicates the last Sunday of the month.
For example:
The string 0 0 13 * * ? indicates that you want to schedule the processor to run at 1:00 PM every day.
The string 0 20 14 ? * MON-FRI indicates that you want to schedule the processor to run at 2:20 PM every Monday through Friday.
The string 0 15 10 ? * 6L 2011-2017 indicates that you want to schedule the processor to run at 10:15 AM, on the last Friday of every month, between 2011 and 2017.
For your schedule time should be like below;
0109*?** - this meaning every 1 seconds 09 minutes is morning 9 AM other * fields run every day and month.
I hope it helps you!!!
Scheduling Strategy: CRON driven
Run Schedule: 0 0 9 * * ? *

Spring Cron scheduler “disable pattern”

My application loads some cron patterns from a properties file. I'm using the #Scheduled annotation like this:
#Scheduled(cron = "${config.cronExpression:0 0 11,23 * * *}")
Now I want to disable some tasks and the easiest solution would be to enter a cron pattern which will never run.
In order to do this, I thought about using a cron expression that only executes at a specific day in the past.
But unfortunately the Spring cron expressions don't allow to add a year or a date in the past.
Is there any pattern that will never run?
As of Spring 5.1.0 the #Scheduled annotation can accept "-" as the cron expression to disable the cron trigger.
Per the Javadocs:
The special value "-" indicates a disabled cron trigger, primarily meant for externally specified values resolved by a ${...} placeholder.
If it was a cron expression (NOT spring scheduler), you could have used below which makes the cron run on 2099
59 59 23 31 12 ? 2099
But spring scheduler does not take a year as input. This is what I have found to defer it for some extended period. Below will run on 29 Feb which will be a leap year.
0 0 0 29 2 ?
If you're stuck pre Spring 5.1.0 (SpringBoot < 2.1), your only option may be to disable the bean/service with the #Scheduled method altogether, for example by using a #ConditionalOnProperty("my.scheduleproperty.active") annotation and not setting the property (or setting it to false)

CRON: Run job on particular hours

I have a spring batch application and i am using CRON to set how often this application runs. But the problem i am running into is that i want to run the job on specific hours
3 am
7 am
11 am
3 pm
7 pm
11 pm
As you can see it is every 4 hours but starts at 3 am so i cannot use */4 in the hours section of the timing format as this would start the job at 4am
I have also tried '3,7,11,15,19,23' in the hours section but this does not work either (guessing it only works in the minutes section). Does someone know how i can do this?
Use
#Scedule(cron="0 0 3/4 * * ?")
The Pattern x/y means: where <timepart> mod y = x
or
#Scedule(cron="0 0 3,7,11,15,19,21 * * ?")
According to the Quartz Cron Trigger Tutorial:
The '/' character can be used to specify increments to values. For
example, if you put '0/15' in the Minutes field, it means 'every 15th
minute of the hour, starting at minute zero'. If you used '3/20' in
the Minutes field, it would mean 'every 20th minute of the hour,
starting at minute three' - or in other words it is the same as
specifying '3,23,43' in the Minutes field. Note the subtlety that
"/35" does *not mean "every 35 minutes" - it mean "every 35th minute
of the hour, starting at minute zero" - or in other words the same as
specifying '0,35'.
0 0 3,7,11,15,19,23 * * ?
Fires for 0 minute starting at 3am and ending at 23:00 pm every day.
judging by the two answers above the error i was making was i was keeping the apostrophe at the start and end of my hours... very silly
i managed to solve this by using 3-23/4 for the hour as this starts from 3am and then every other fourth hour (just a different way of doing it to the other answers)

spring cronsequencegenerator pattern for job that run on 9th, 16th, 23th and 30th of every month at 10 O'clock.

I am struggling with the spring cronsequencegenerator pattern for job that run on 9th, 16th, 23th and 30th of every month at 10 O'clock.
Please help.
Spring provides a solution
Go through the documentation of Scheduled annotation and you be able to solve your problem.
Assuming it's 10AM and not 22:00 basic cron exp for you would be
0 10 9,16,23,30 * *
As per documentation cron-like exp is needed
0 0 10 9,16,23,30 * * - with additional first field for seconds.
Depending on specification (implementation) of "cron-like" your needs could suit
0 0 10 9,16,23,30 * ? - with day of the week special symbol
0 0 10 9,16,23,30 * * * - with optional field for year filled in

bash : Make job every x days

I have a bash script runned every day via cron.
In this bash I want to run some command but only every x day (x is fixed and will be 3, 4 or 5 I don't know at the moment)
I can test if the remainder of the division day of month / x equal 0
day_of_month % x = 0
I will work on a single month but not always between to month, for example months april - may with x = 3
1 2 3 4 5 6 7 8 9 ... 27 28 29 30 31 1 2 3 4 5 6 7 8 9 ... 27 28 29 30
x x x ... x x x x x ... x x
It not a big deal, but is there any other way to do this ?
PS : I don't want to explode my script and make 2 cron jobs (one every day : *, the other evevery x day : */x)
One easy solution would be to use "day of year" instead of day of month. Then there'd be no problem with different month lengths. You'd still get problems at the end of year, of course.
The "day of year" is available via date +%j.
If that is still not acceptable, you can use the seconds since 1970 (date +%s), and divide by days*24*60*60, then use the remainder of that. You'd still get problems with leap seconds, but otherwise it should be correct.
Using cron sounds the like the proper idea actually, because that is what cron is made for.
One idea though to solve your 'across months' problems: don't think in months, instead check whether the time-in-seconds-since-epoch % x*seconds-per-day is 0 ...
I would export a system variable with last date of execution and calculate the interval from it. It wouldn't work after a restart but I assume in this case the interval should be restored.
Have a look at the at command
Using that you can tell a script to call itself at a later date.
From manpage:
For example, to run a job at 4pm three
days from now, you would do at
4pm + 3 days, to run a job at 10:00am on July 31, you would do at
10am
Jul 31 and to run a job at 1am tomorrow, you would do at 1am
tomorrow.
If I had this problem, I would tell cron to run my script once every day, and inside the script I would calculate whether or not work needs to be done. That way, you have full control over it.
For example,
dayno=`date +%d`
let divided=daynum%3
if [ $divided == 0 ] ; then
exit 0
fi
# real work begins here
This script would work on any system that uses bash.
Does your job need to run every day? That is, does it do something on those days when your calculation does not result in a 0. If not, you could set up a job in cron thus:
0 12 3,6,9,12,15,18,21,24,27,30 * * <your job>
and it would run every third day (at 12 noon in my example).
I'm pretty sure that "Feb 30" would be safely ignored.

Resources