spring-scheduled-tasks
The @Scheduled Annotation in Spring
1. Overview
In this article we’ll discuss the Spring @Scheduled annotation – we will illustrate how it can be used to configure and schedule tasks.
The simple rules that need to be followed to annotate a method with @Scheduled are:
-
a method should have void return type
-
a method should not accept any parameters
Further reading:
How To Do @Async in Spring
How to enable and use @Async in Spring – from the very simple config and basic usage to the more complex executors and exception handling strategies.
A Guide to the Spring Task Scheduler
A quick and practical guide to scheduling in Spring with Task Scheduler
2. Enable Support for Scheduling
To enable the support for scheduling tasks and the @Scheduled annotation in Spring – we can use the Java enable-style annotation:
@Configuration
@EnableScheduling
public class SpringConfig {
...
}
Or we can do the same in XML:
<task:annotation-driven>
3. Schedule a Task at Fixed Delay
@Scheduled(fixedDelay = 1000)
public void scheduleFixedDelayTask() {
System.out.println(
"Fixed delay task - " + System.currentTimeMillis() / 1000);
}
In this case, the duration between the end of last execution and the start of next execution is fixed. The task always waits until the previous one is finished.
This option should be used when it’s mandatory that the previous execution is completed before running again.
4. Schedule a Task at a Fixed Rate
@Scheduled(fixedRate = 1000)
public void scheduleFixedRateTask() {
System.out.println(
"Fixed rate task - " + System.currentTimeMillis() / 1000);
}
This option should be used when each execution of the task is independent.
Note that scheduled tasks don’t run in parallel by default. So even if we used fixedRate, the next task won’t be invoked until the previous one is done.
If we want to support parallel behavior in scheduled tasks, we need to add the @Async annotation:
@EnableAsync
public class ScheduledFixedRateExample {
@Async
@Scheduled(fixedRate = 1000)
public void scheduleFixedRateTaskAsync() throws InterruptedException {
System.out.println(
"Fixed rate task async - " + System.currentTimeMillis() / 1000);
Thread.sleep(2000);
}
}
Now this asynchronous task will be invoked each second, even if the previous task isn’t done.
5. Fixed Rate vs Fixed Delay
We can run a scheduled task using Spring’s @Scheduled annotation but based on the properties fixedDelay and fixedRate the nature of execution changes.
The fixedDelay property makes sure that there is a delay of n millisecond between the finish time of an execution of a task and the start time of the next execution of the task.
This property is specifically useful when we need to make sure that only one instance of the task runs all the time. For dependent jobs, it is quite helpful.
The fixedRate property runs the scheduled task at every n millisecond. It doesn’t check for any previous executions of the task.
This is useful when all executions of the task are independent. If we don’t expect to exceed the size of the memory and the thread pool, fixedRate should be quite handy.
But, if the incoming tasks do not finish quickly, it’s possible they end up with “Out of Memory exception”.
6. Schedule a Task with Initial Delay
@Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void scheduleFixedRateWithInitialDelayTask() {
long now = System.currentTimeMillis() / 1000;
System.out.println(
"Fixed rate task with one second initial delay - " + now);
}
Note how we’re using both fixedDelay as well as initialDelay in this example. The task will be executed a first time after the initialDelay value – and it will continue to be executed according to the fixedDelay.
This option comes handy when the task has a set-up that needs to be completed.
7. Schedule a Task Using Cron Expressions
Sometimes delays and rates are not enough, and we need the flexibility of a cron expression to control the schedule of our tasks:
@Scheduled(cron = "0 15 10 15 * ?")
public void scheduleTaskUsingCronExpression() {
long now = System.currentTimeMillis() / 1000;
System.out.println(
"schedule tasks using cron jobs - " + now);
}
Note – in this example, that we’re scheduling a task to be executed at 10:15 AM on the 15th day of every month.
8. Parameterizing the Schedule
Hardcoding these schedules is simple, but usually, you need to be able to control the schedule without re-compiling and re-deploying the entire app.
We’ll make use of Spring Expressions to externalize the configuration of the tasks – and we’ll store these in properties files:
A fixedDelay task:
@Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds}")
A fixedRate task:
@Scheduled(fixedRateString = "${fixedRate.in.milliseconds}")
A cron expression based task:
@Scheduled(cron = "${cron.expression}")
9. Configuring Scheduled Tasks Using XML
Spring also provides XML way of configuring the scheduled tasks – here is the XML configuration to set these up:
<!-- Configure the scheduler -->
<task:scheduler id="myScheduler" pool-size="10" />
<!-- Configure parameters -->
<task:scheduled-tasks scheduler="myScheduler">
<task:scheduled ref="beanA" method="methodA"
fixed-delay="5000" initial-delay="1000" />
<task:scheduled ref="beanB" method="methodB"
fixed-rate="5000" />
<task:scheduled ref="beanC" method="methodC"
cron="*/5 * * * * MON-FRI" />
</task:scheduled-tasks>
10. Conclusion
We covered the process to enable scheduling and various ways of configuring scheduling task patterns.
The examples shown can be found over on GitHub.