Spring Scheduler
In this article, we will understand how to schedule tasks in Spring so that they are executed repeatedly using @Scheduled
annotation with example programs.
Scheduling means executing tasks repeatedly at a fixed time and/or interval automatically. To enable scheduling in a Spring boot application, below configuration is required
1. @EnableSchduling annotation
Apply @EnableScheduling
annotation over main class of the application or any @Configuration
class as shown below
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class DatamigrationApplication { }
2. @Scheduled annotation
Apply @Scheduled
annotation over the method that needs to scheduled. This method shall contain the task to be executed repeatedly.
Methods with @Scheduled
annotation should fulfill following two conditions:
I. It should not accept any arguments.
If method with @Scheduled
is provided with arguments, the application throws following error at startup
java.lang.IllegalStateException: Encountered invalid @Scheduled method ‘repeat’: Only no-arg methods may be annotated with @Scheduled
II. It should not return any value
Return type of @Scheduled
method should be void
, that is, it should not return any value.
Even if the method returns a value, this will not be any error, but the value returned will be ignored.
@Scheduled options
Spring boot supports following options for scheduling tasks
1. At fixed rate
Tasks are executed at fixed time interval. Tasks keep on executing at given interval and there is no relation between previous and next tasks.
So, with fixed rate of 2 seconds, tasks will keep on executing every 2 seconds even if each task takes 5 seconds.
This is done by providing fixedRate
attribute followed by the interval in milliseconds with @Scheduled
.
Example,
@Scheduled(fixedRate = 5000) void repeat() { try { LocalDateTime now = LocalDateTime.now(); System.out.println("Repeated at: " + now.getHour() + ":" + now.getMinute() + ":" + now.getSecond()); // sleep for 10 seconds Thread.sleep(10000); System.out.println("---- Task completed ----"); } catch (InterruptedException e) { e.printStackTrace(); } }
Here, sleep()
is used to represent a task that takes 10 seconds.
Look at the below output to understand the working of fixedRate.
Repeated at: 15:1:16
—- Task completed —-
Repeated at: 15:1:26
—- Task completed —-
Repeated at: 15:1:36
—- Task completed —-
Repeated at: 15:1:46
—- Task completed —-
Repeated at: 15:1:56
—- Task completed —-
Repeated at: 15:2:6
—- Task completed —-
Repeated at: 15:2:16
You can also provide a string value to fixedRate. But, it should be parseable to numeric format. Example, fixedRate = "5000"
.
Note that even the method is scheduled with fix rate of 5 seconds and the task takes 1o seconds, the next task did not start after 5 seconds.
This is because by default tasks do not run in parallel.
To enable parallel scheduling, add
@EnableAsync
annotation over the class and @Async
annotation over the method with @Scheduled
as below.
@EnableScheduling @EnableAsync public class SchedulerExample { @Scheduled(fixedRate = 5000) void repeat() { try { LocalDateTime now = LocalDateTime.now(); System.out.println("Repeated at: " + now.getHour() + ":" + now.getMinute() + ":" + now.getSecond()); // sleep for 10 seconds Thread.sleep(10000); System.out.println("---- Task completed ----"); } catch (InterruptedException e) { e.printStackTrace(); } } }
Output now will change to
Repeated at: 15:13:14
Repeated at: 15:13:19
—- Task completed —-
Repeated at: 15:13:24
—- Task completed —-
Repeated at: 15:13:29
Repeated at: 15:13:34
—- Task completed —-
Repeated at: 15:13:39
—- Task completed —-
Repeated at: 15:13:44
—- Task completed —-
Note that new task is started after every 5 seconds(fixedRate
interval) irrespective of the status of current executing task.
2. At fixed delay
Tasks are executed with a delay of given time interval between them.
With fixed delay of 5 seconds, a task will start 5 seconds after the current executing task completes, irrespective of the time taken by the executing task.
Fixed delay is configured using fixedDelay
attribute with @Scheduled
. Example,
@Scheduled(fixedDelay = 5000) public void repeat() { try { LocalDateTime now = LocalDateTime.now(); System.out.println("Repeated at: " + now.getHour() + ":" + now.getMinute() + ":" + now.getSecond()); Thread.sleep(10000); System.out.println("---- Task completed ----"); } catch (InterruptedException e) { e.printStackTrace(); } }
Look at the output below to understand fixedDelay
Repeated at: 15:18:54
—- Task completed —-
Repeated at: 15:19:9
—- Task completed —-
Repeated at: 15:19:24
—- Task completed —-
Repeated at: 15:19:39
—- Task completed —-
Repeated at: 15:19:54
—- Task completed —-
Repeated at: 15:20:9
That is, with a fixed delay of 5 seconds, if the current executing task completes at 10:30 AM, next task will begin at 10:35 AM.
And, if this task takes 10 seconds, then the next task will begin at 10:45 AM and so on.
Thus, with fixedDelay
, new task will start at
Time at which the current executing task completes + delay time
Suppose you want to schedule tasks starting after some interval. @Scheduled provides an initialDelay attribute with both fixedRate and fixedDelay, which is applicable for the first task. Example,
@Scheduled(fixedRate = 1000, initialDelay = 2000)
This will start the first task after 2 seconds. After that, all tasks will execute at fixed interval of 1 seconds.
3. Cron expression
A cron expression is very powerful and can be used to schedule tasks at particular time or even at some date, month or year etc.
Cron expression is a UNIX format cron expression consisting of 6 value types or fields as shown below
where, possible values in each field are:
Second, Minute: May be a value between 0 and 59.
Hour: May be a value between 0 and 23.
Day of Month: A value between 1 and 31.
Month: A value between 1 and 12 or Names such as JAN, FEB etc.
Day of Week: Value between 0 and 7 or Names such as SUN, MON etc., where 0 and 7 stand for SUN.
Following special characters are supported in a CRON expression
* : All possible values in a field.
– : Range of values. Example, 9-11 in hour field means execute from 9 AM to 11 AM.
, : Specify multiple values. Example, 9,10,11 in hour field means execute from 9, 10 and 11 AM.
/ : Specifying interval or step size. Example, */10 in seconds field means execute a task every 10 seconds.
? : Can be used in only day of month or day of week fields. It is used as a substitute to ignore the field value. Example, to execute a task on 20th of every month, specify 20 in day of month field and ? in day of week field since we do not care about the day.
Cron expression examples
Below is a list of some cron expressions and their meanings.
- * * * * * *
Execute at every second. - 0 * * * * *
At first second of every minute. - 0 0 * * * *
Execute at first second of first minute of every hour. That is, as 00:00:00, 01:00:00, 02:00:00 etc. - */10 * * * * *
Execute at every ten seconds. - * */5 * * * *
Execute every 5 minutes. - 0 0 8-10 * * *
8, 9 and 10 o’clock of every day. - 0 0 6,19 * * *
6:00 AM and 7:00 PM every day. - 0 0/30 8-10 * * *
8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 AM every day. - 0 0 9-17 * * MON-FRI
Every hour nine-to-five weekdays. - 0 0 0 25 12 ?
Every Christmas Day at midnight or 00:00. - 0 0 8 1 1 MON, TUE
Execute a task on 1 Jan at 8 AM, if it falls on Monday or Tuesday.
You can sense that a cron expression is much more powerful that fixedRate
and fixedDelay
attributes.
Example of scheduling with cron expression is
@Scheduled(cron = "* 0 * * * *") public void repeat1() { try { LocalDateTime now = LocalDateTime.now(); System.out.println("Repeated at: " + now.getHour() + ":" + now.getMinute() + ":" + now.getSecond()); System.out.println("---- Task completed ----"); } catch (Exception e) { e.printStackTrace(); } }
Above method will execute at first second of every minute as evident from the below output
Repeated at: 20:57:0
—- Task completed —-
Repeated at: 20:58:0
—- Task completed —-
Repeated at: 20:59:0
—- Task completed —-
Repeated at: 21:0:0
—- Task completed —-
Default time zone taken by cron is the system time zone. To specify a different time zone, use zone
attribute with cron
as
@Scheduled(cron = "* * * * * *", zone="America/Los_Angeles"
It is a better practice to control schedule time from properties file instead of writing them in code. This can be done as
@Scheduled(fixedRate="${fixed.rate.value}") @Scheduled(fixedDelay="${fixed.delay.value}") @Scheduled(cron="${cron.exp}")
and providing these properties in application.properties file of your application as shown below.
fixed.rate.value=2000 fixed.delay.value=1000 cron.exp=0 * * * * *
That is all on scheduling tasks in Spring boot with @Scheduled
annotations at fixed rate, fixed delay and cron expresssions with example programs.
Hope the article was useful.