Want to Execute Task on Scheduled Period ? Spring Boot Scheduler

Shubham Wankhede
6 min readMar 9, 2023

performing any task on scheduled basic i.e it can be either on regular interval or certain delay or certain time and date can be one of crucial operation in any programming language.

we can use perform tasks on scheduled basis to remove unwanted entries from database, update in-memory cache on regular interval or many more operations.

we have different schedulers available with us to work with like Quartz scheduler but while working with spring one most easy way to perform task on scheduled basic is by using spring boot scheduler, so understand how to use the spring boot scheduler in this blog.

we don’t need any special starter or dependency to be imported to work with spring boot scheduler, it comes with basic parent starter, you can check different scheduler class in spring context library

before we use any spring boot scheduler annotation for scheduling task we have to enable the scheduling in our application for that we have to use @EnableScheduling annotation on top of any configuration class.

@Configuration
@EnableScheduling
public class SchedulerConfig {
}

now we are ready to use the scheduling on any method.

To perform scheduling on any task we have add @Scheduled annotation on top of method.

by configuring different attributes of @Scheduled annotation we can change the behaviour of scheduling, let’s learn them as well

all values we are providing below are in the form of miliseconds

  1. Fixed Delay

whenever we want want to perform a task repeatedly such that once task is completed after a certain delay we want to execute same task then we can use the fixed delay attribute in @Scheduled annotation

@Scheduled(fixedDelay = 5000)
public void printUsers() {
List<User> users = userRepo.findAll();
users.stream().forEach(System.out::print);
}

values are in the form of millis

one thing to remember here in fixed delay attribute is that it waits for the complete execution of task to start counter for fixed delay.

2. Fixed Rate

We understood that if we want to execute a repeated task with a delay after completion of every task we can use fixedDelay attribute in @Scheduled task

but what if I don’t want to wait for the completing every task, I just want to execute a task after every 5 sec without waiting for completion of previous task, well in this case you can use fixedRate attribute

@Scheduled(fixedRate = 5000)
public void printUsers() {
List<User> users = userRepo.findAll();
users.stream().forEach(System.out::print);
}

3. Initial Delay

In case you want to provide some initial delay before the start of first task then we can do it using initialDelay attribute

it is usually provided so that before our task starts all configurations should be complete or some record additon task should be executed first.

@Scheduled(fixedDelay = 5000, initialDealy = 5000)
public void printUsers() {
List<User> users = userRepo.findAll();
users.stream().forEach(System.out::print);
}

4. Fixed Delay String and Fixed Rate String

In case the value we want to provide to @Scheduled annotation is too large may in hours, in that case we shouldn’t provide the values in numbers we can use respective string methods in this usecase.

fixedDealyString — 1 Hour Delay

@Scheduled(fixedDelayString = "PT1H")
public void printUsers() {
List<User> users = userRepo.findAll();
users.stream().forEach(System.out::print);
}

fixedRateString — 5 sec Delay

@Scheduled(fixedRateString = "PT5S")
public void printUsers() {
List<User> users = userRepo.findAll();
users.stream().forEach(System.out::print);
}

Note : for all above values can be replace with placeholder from value can be picked up from properties file

@Scheduled(fixedDelay = "${application.fixed.deplay}")
@Scheduled(fixedRate = "${application.fixed.rate}")
@Scheduled(fixedDelayString = "${application.fixed.deplay.string}")
@Scheduled(fixedRateString = "${application.fixed.rate.string}")

5. Cron Expressions

if your scheduled interval is too simple or too small then it’s ok to use above approach but if we want to go for more specific approach we have to go for cron expression.

whenever you are working with cron expression we have to use cron attribute with values as string which itself have six/seven values with space separation

so to say it simply cron is string with 6 or 7 fields separated by white space

ex :

@Scheduled(cron = "* * * * * *")

let’s understand the meaning of every field (*) in the string.

depending on how many fields you are using the meaning of these field changes, if you are using 6 fields then Year field is neglected

also understand the different special character and which once can be used where.

Field Name      Mandatory   Allowed Values      Allowed Special Characters
Seconds YES 0-59 , - * /
Minutes YES 0-59 , - * /
Hours YES 0-23 , - * /
Day of month YES 1-31 , - * ? / L W
Month YES 1-12 or JAN-DEC , - * /
Day of week YES 1-7 or SUN-SAT , - * ? / L #
Year NO empty, 1970-2099 , - * /

Some Special Characters and there meaning

  1. * : all possible values for field
  2. ? (Question Mark) : is arbitrary and will be neglected whenever used
  3. / (Forward Slash) : increment values, i.e if used in sec which can vary between 0–59 ex. 5/15 — starting from from 5 sec increment every 15 sec i.e. 5,20,35,50.
  4. , (Comma) : used to specify multiple values used in minute 5,10 tells us 5 minute and 10 minute individually
  5. - (Hyphen) : used to specify value range ex. 5–10 in mutes specify evert minute starting from 5 minute to 10 minute
  6. L : has last meaning depending on which field it is used.
  7. # : to specify nth occurance of weekday of month ex. 4th Monday of month can written as 2#4

let’s write some cron expressions and there meaning with 6/7 fields.

// run task every 15 sec - 6 fields
@Scheduled(cron = "*/15 * * * * *")

// run task 12:00 non everyday
@Scheduled(cron = "0 12 * * * *")

// run task at every minute starting from 3:00 to 3:10
@Scheduled(cron = "0 0-10 15 * * *")

// run task at 1:15 and 1:45 from Monday to Friday in June
@Scheduled(cron = "0 15,45 13 ? 6 MON-FRI")

// run task at 1:15 on last day of every month
@Scheduled(cron = "0 15 13 L * ?")

// run task at 1:15 on last day of every month
@Scheduled(cron = "0 15 13 L * ?")

// run task at 1:15 on third friday of every month. (SUN-SAT : 1-7)
@Scheduled(cron = "0 15 13 ? * 6#3")

Passing values through properties file

instead of hardcoding the value for cron expression you use placeholder and pass the value from application.properties file

@Scheduled(cron = "${application.scheduler.cron.expression}")

application.properties

application.scheduler.cron.expression = * * * * * *

Working with Macros in cron expression

while working with cron the best option is to work with cron expression, but spring provides us with one more approach and i.e. to use macros in cron to increase the readability

spring boot scheduler cron macros

Using Threads from Thread Pool to run task

By default spring boot scheduler uses 1 thread to execute the different task but in case you are in need to use multiple thread to run your task so that if one thread is blocked it should not hamper the execution of other tasks you can configure the spring boot scheduler to use multiple threads

there are 2 approaches we can follow either through application.properties file or creating instance of ThreadPoolTaskScheduler and setting the value of pool size and returning the instance through @Bean method

  1. Through application.properties file the thread pool size can be directly specified using below property
spring.task.scheduling.pool.size= 3

2. Using ThreadPoolTaskScheduler

@Bean
public TaskScheduler concurrentTaskScheduler(){
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(Integer.valueOf(3));
//taskScheduler.setPoolSize(Integer.valueOf("${app.thread.size}"));
return taskScheduler;
}

once we are with above, we are good to work with Spring Boot scheduler

Hope you enjoyed the blog.

--

--