Prevent Spring Schedulers run at the same time - spring

I have three Spring Schedulers like as shown below
Scheduler 1 (Runs every 15 min)
#Scheduled(cron = "0/15 * * * *")
public void scheduler1() {
// some logic
}
Scheduler 2 (Runs every 20 min)
#Scheduled(cron = "0/20 * * * *")
public void scheduler2() {
// some logic
}
Scheduler 3 (Runs every 25 min)
#Scheduled(cron = "0/25 * * * *")
public void scheduler3() {
// some logic
}
The schedulers are working fine, but there are times in sometimes they will run at the same time which will create some issues. I would like to know if there is any way in which we can prevent more than one scheduler to execute at a time in Spring

Related

Single Cron expression to run a scheduled task between 14:30 to 15:30 for every 5 mins on FRI & SAT in Spring Boot?

Is it possible to run a scheduled task between 14:30 to 15:30 for every 5 mins on Friday & Saturday using a single Cron expression in Spring Boot?
If not, what is the best possible way to achieve this with or without Cron in Spring boot 2?
Note: I have already come up with the below approach however it makes two schedulers.
Scheduler 1: 0 30-59/5 14 ? * FRI,SAT *
Scheduler 2: 0 0-30/5 15 ? * FRI,SAT *
This should work in Spring 5.3
https://spring.io/blog/2020/11/10/new-in-spring-5-3-improved-cron-expressions.
Edited 1: change seconds to 0
#Scheduled("0 30/5 14-15 * * FRI-SAT")
public void run(){
...
}
Edited 2:
#Configuration
#RequiredArgsConstructor
public class SchedulerConfig {
private final TaskScheduler taskScheduler;
private final MyService myService;
#Bean
public ApplicationRunner runner() {
return args -> {
taskScheduler.schedule(myService::run, new CronTrigger("0 30-59/5 14 ? * FRI,SAT *"));
taskScheduler.schedule(myService::run, new CronTrigger("0 0-30/5 15 ? * FRI,SAT *"));
}
}

Spring Boot Scheduler fixedDelay and cron

I'm running a spring boot scheduled process that takes 5-10 seconds to complete. After it completes, 60 seconds elapse before the process begins again (Note that I'm not using fixedRate):
#Scheduled(fixedDelay=60_000)
Now, I want to limit it to run every minute Mon-Fri 9am to 5pm. I can accomplish this with
#Scheduled(cron="0 * 9-16 ? * MON-FRI")
Problem here is that this acts similar to fixedRate - the process triggers EVERY 60 seconds regardless of the amount of time it took to complete the previous run...
Any way to to combine the two techniques?
it worked for me like this
I created a bean that returns a specific task executor and allowed only 1 thread.
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Bean(name = "movProcTPTE")
public TaskExecutor movProcessualThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
exec.setMaxPoolSize(1);
exec.initialize();
return exec;
}
}
In my service, I injected my task executor and wrapped my logic with it, so even though my schedule runs every minute, my logic will only run when the task executor is free.
#Service
#EnableScheduling
public class ScheduledService {
#Autowired
private ReportDataService reportDataService;
#Autowired
private AsyncService async;
#Autowired
#Qualifier("movProcTPTE")
private TaskExecutor movProcTaskExecutor;
#Scheduled(cron = "0 * * 1-7 * SAT,SUN")
public void agendamentoImportacaoMovProcessual(){
movProcTaskExecutor.execute(
() -> {
reportDataService.importDataFromSaj();
}
);
}
}
try this:
#Schedules({
#Scheduled(fixedRate = 1000),
#Scheduled(cron = "* * * * * *")
})
You can try this one:
#Scheduled(cron="1 9-16 * * MON-FRI")
Also you can try write correct on this site https://crontab.guru/
You can pass fixed delay (and any other number of optional parameters) to the annotation, like so:
#Scheduled(cron="0 * 9-16 ? * MON-FRI", fixedDelay=60_000)
From the documentation: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html

Use .yml variable into #Scheduled(cron = variable)

I got a groovy class
#Configuration
class SchedulerTest {
SomeService service
#Inject
SchedulerTest (SomeService service) {
this.service = service
}
#Scheduled(cron = '0/5 * * * * *')
void doSomething() {
service.someMethod()
}
}
and got a .yml file
scheduler:
cron: 0/5 * * * * *
I want to use the .yml variable to the cron value into #Scheduled, like
#Scheduled(cron = schdulers.cron)
How can I make this work?
Obs. I`m very new in development.
Put
#Scheduled(cron = '${scheduler.cron}')
void doSomething() {
service.someMethod()
}
With the parameter in single quotes
With double quotes, groovy is trying to evaluate the template

Spring Boot #Scheduled running twise

I have a scheduler which runs everyday once at 8.01pm. But i would seem that when it runs at 8.01pm it run twice. Following is my code
#Scheduled(cron = "0 1 20 * * *")
public void reportCurrentTime() {
logger.info("started");
}
Can anyone help me to fix my problem.Thanks.

Call a method on a specific dates using ThreadPoolTaskExecutor

I have a method that I wish to run once using Spring and it needs to run on a given java.util.Date (or LocalDateTime alternatively). I am planning to persist all of the dates that the method should execute to a data source. It should run asynchronously.
One way is to check the DB every day for a date and execute the method if the date has passed and hasn't been executed. Is there a better way?
I know that Spring offers a ThreadPoolTaskScheduler and a ThreadPoolTaskExecutor. I am looking at ScheduledFuture schedule(Runnable task, Date startTime) from the TaskScheduler interface. Would I need to create a Runnable Spring managed bean just to call my method? Or is there a simpler annotation that would do this? An example would really help.
(Looked here too.)
By externalizing the scheduled date (to a database), the typical scheduling practices (i.e. cron based, or fixed scheduling) no longer apply. Given a target Date, you can schedule the task accurately as follows:
Date now = new Date();
Date next = ... get next date from external source ...
long delay = next.getTime() - now.getTime();
scheduler.schedule(Runnable task, delay, TimeUnit.MILLISECONDS);
What remains is to create an efficient approach to dispatching each new task.
The following has a TaskDispatcher thread, which schedules each Task based on the next java.util.Date (which you read from a database). There is no need to check daily; this approach is flexible enough to work with any scheduling scenario stored in the database.
To follow is working code to illustrate the approach.
The example Task used; in this case just sleeps for a fixed time. When the task is complete, the TaskDispatcher is signaled through a CountDownLatch.
public class Task implements Runnable {
private final CountDownLatch completion;
public Task(CountDownLatch completion) {
this.completion = completion;
}
#Override
public void run() {
System.out.println("Doing task");
try {
Thread.sleep(60*1000); // Simulate the job taking 60 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
completion.countDown(); // Signal that the job is complete
}
}
The dispatcher is responsible for reading the database for the next scheduled Date, launching a ScheduledFuture runnable, and waiting for the task to complete.
public class TaskDispatcher implements Runnable {
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private boolean isInterrupted = false;
#Override
public void run() {
while (!isInterrupted) {
Date now = new Date();
System.out.println("Reading database for next date");
Date next = ... read next data from database ...
//Date next = new Date(); // Used as test
//next.setTime(now.getTime()+10*1000); // Used as test
long delay = next.getTime() - now.getTime();
System.out.println("Scheduling next task with delay="+delay);
CountDownLatch latch = new CountDownLatch(1);
ScheduledFuture<?> countdown = scheduler.schedule(new Task(latch), delay, TimeUnit.MILLISECONDS);
try {
System.out.println("Blocking until the current job has completed");
latch.await();
} catch (InterruptedException e) {
System.out.println("Thread has been requested to stop");
isInterrupted = true;
}
if (!isInterrupted)
System.out.println("Job has completed normally");
}
scheduler.shutdown();
}
}
The TaskDispatcher was started as follows (using Spring Boot) - start the thread as you normally do with Spring:
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor(); // Or use another one of your liking
}
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
return new CommandLineRunner() {
public void run(String... args) throws Exception {
executor.execute(new TaskDispatcher());
}
};
}
Let me know if this approach will work for your use case.
Take a look at the #Scheduled annotation. It may accomplish what you're looking for.
#Scheduled(cron="*/5 * * * * MON-FRI")
public void scheduledDateWork() {
Date date = new Date(); //or use DAO call to look up date in database
executeLogic(date);
}
Cron Expression Examples from another answer:
"0 0 * * * *" = the top of every hour of every day.
"*/10 * * * * *" = every ten seconds.
"0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.
"0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.
"0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays
"0 0 0 25 12 ?" = every Christmas Day at midnight

Resources