Spring Cron scheduler “disable pattern” - spring

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)

Related

spring boot #scheduled triggered after the time expected

I try to trigger a task every day at 7h45 in spring boot by this way
#Scheduled(cron = "45 7 * * * ?")
public void method() {....}
And I saw this morning that it triggered at around 9h09.
I checked that server time correspond to the time displayed on my computer. Furthermore the server is running on windows
So Why this difference of time ?
The first element in Spring cron expressions are seconds.
So I assume that it was run at 9:07:45
This would be the correct expression:
0 45 7 * * ?
Check out: https://spring.io/blog/2020/11/10/new-in-spring-5-3-improved-cron-expressions

Spring #Scheduled, how to run once at time (not concurrently)

I have an annotated method width #Scheduled with an cron of */15 * * * * ? (run each 15 seconds).
Sometimes this process take more than 15 seconds to run.
Is there any way to avoid the call of the #Scheduled if it's already running?
My workaround currently is a flag field in the class to signal if the process is running, and if it is marked the code exits before execute the main code.
I think it's already the case, if the first job has'nt finished, the second will not start.
See :
How to prevent overlapping schedules in Spring?
If it isn't working, you can also use an AtomicBoolean to check if you must start the process or not.

Spring scheduled work at 21:30 gmt+3

I'm trying to trigger a method with spring #Scheduled . I thought i should use zone but nothing happens. By the way I'm increasing minute like 30,31,32 for test also tried for gmt+2 and gmt+3.
This is the annotation i try-->
#Scheduled(cron = "0 30 21 * * * " , zone="Europe/Moscow")
Anyone know why ? Where did i go wrong ? Thanks in advance
You have set when the scheduler is to run, but possibly not actually enabled it.
Add #EnableScheduling to where you have defined your main Application class.

quartz spring cron trigger fire immediately

I have a spring application that uses quartz cron trigger. I have given the following for frequency 0 0/20 * * * ?.....once every 20 min. But i want the first one to run immediately. Right now, when I start the application, it runs after 20 min. I was hoping it would run asap and then after 20 min.
Thanks in advance.
It sounds like you want to use an interval trigger (SimpleTrigger in Quartz can do the job).
The CronTrigger wants you to specify the minutes at which to run.
So your trigger schedule says: start at 0 minutes, and run every 20 minutes after that until the hour is over. Then start at 0 again.
But with the SimpleTrigger, you say - start now and run every 20 minutes.
Here is a tutorial on SimpleTrigger:
http://quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-05
Here is a tutorial on CronTrigger:
http://quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
You don't need CRON expression (and Quartz at all!) to run given code every 20 minutes. Just use fixed rate (Spring built-in):
#Scheduled(fixedRate=20 * 60 * 1000)
That's it! By default first invocation happens immediately, second after 20 minutes. Since Spring 3.2 you can even say initialDelay=10000 to run for the first time after exactly 10 seconds.
If you really want to use Quartz, check out SimpleTrigger.

Quartz: Cron expression that will never execute

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_*

Resources