How to Implement Scheduled Task in Spring
- Details
- Written by Nam Ha Minh
- Last Updated on 18 July 2024   |   Print Email
In this post, I’d like to guide you on implementing scheduled tasks in the Spring framework with various code examples and configurations. In other words, you’ll learn how to enable scheduling for some code that needs to be executed periodically, such as every 30 minutes or every Monday at 2:00 AM.
Some real-life examples of scheduled tasks are:
- automatically backing up important data once a day
- automatically sending promotional emails once a week
- cleaning up expired refresh tokens (REST API)
- …
In the code examples below, you’ll see how to use @EnableScheduling and @Scheduled annotations with configuration elements such as initialDelay, fixedDelay, fixedRate, etc., to implement scheduled tasks in a Spring Boot application. You will also learn how to change time unit, configure intervals in configuration file, and specify cron-like expressions.
1. Spring Scheduled Task Quick Examples
The following code example illustrates a task scheduled to be executed every 30 seconds:
package net.codejava; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component @EnableScheduling public class MyScheduledTask { @Scheduled(fixedDelay = 30_000) public void execute() { // code is scheduled to be executed periodically } }
Here, we annotate a component class with the @EnableScheduling annotation, which enables Spring’s scheduled task execution capability. It tells Spring to detect @Scheduled annotations on any managed beans in the container.
In the above example, the execute() method is marked with the @Scheduled annotation. When Spring detects this method, it will create a task executor scheduled to be executed every 30,000 milliseconds (30 seconds), as specified by the fixedDelay attribute. And when the task executor runs, it calls the marked method. Makes sense?
Let’s see another example. You can also implement task execution logic in a separate class like this:
package net.codejava; import org.springframework.scheduling.annotation.Scheduled; public class MyTask { @Scheduled(fixedRate = 1_800_000) public void work() { // task execution logic } }
This task is scheduled to be executed periodically at an interval of 30 minutes, specified by the fixedRate attribute (you’ll learn the difference between fixedDelay and fixedRate shortly). Then, declare a bean of this class in a configuration class as shown below:
package net.codejava; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration @EnableScheduling public class AppConfig { @Bean public MyTask myTask() { return new MyTask(); } }
Depending on your preferences and application’s needs, you can choose either or both approaches: implement scheduled tasks in configuration or component classes, or in a separate class that will be instantiated as a managed bean.
Next, let’s see how to customize task scheduling with options such as initial delay, fixed delay, fixed rate, and more.
2. Specify initial delay time
In the above code examples, the scheduled tasks will be executed the first time immediately when the application starts. If you want to have some delay before the first execution, use the initialDelay attribute of the @Scheduled annotation, as follows:
public class MyTask { @Scheduled(initialDelay = 300_000, fixedRate = 1_800_000) public void work() { // task execution logic } }
Here, this task is set to be delayed by about 5 minutes (300,000 milliseconds) before the first execution. Then it will be executed every 30 minutes. Note that the default time unit is milliseconds.
3. Difference between fixedDelay and fixedRate
The fixedDelay attribute specifies a fixed period between the end of the last invocation of the task and the start of the next invocation. This means that no matter how long a single execution of the task takes, the delay time between executions are always constant. In other words, the next execution must wait the current one is complete.
And the fixedRate attribute specifies a fixed period between invocations of the task. This means the task will be executed exactly at the specified interval, regardless of how long the execution of each invocation takes. In other words, there can be a chance that two or more executions running in parallel if the execution time is longer than the fixed period.
So, understanding the difference between fixedDelay and fixedRate allows you to choose the one best suits your application’s needs. Use fixedDelay if overlapping executions are not allowed. Use fixedRate if the task must run exactly at the specified interval and overlapping executions do not matter.
Note that you can use both fixedRate and fixedDelay attributes at the same time. Use either one.
4. Change time unit
The default time unit for intervals is milliseconds, but you can change it to minutes, hours or days. The following example shows how to set the time unit to minutes:
package net.codejava; import java.util.concurrent.TimeUnit; import org.springframework.scheduling.annotation.Scheduled; public class MyTask { @Scheduled(initialDelay = 5, fixedRate = 30, timeUnit = TimeUnit.MINUTES) public void work() { // task execution logic } }
This is more understandable, right? This task is set to be executed every 30 minutes with initial delay time is 5 minutes. You can even set time unit to microseconds or nanoseconds.
5. Schedule one-time task
To schedule a task to be executed only once, specify only the initialDelay attribute. For example:
public class MyTask { @Scheduled(initialDelay = 100_000) public void work() { // this task will be executed only once, after 100 seconds } }
You can also change the time unit for a one-time task:
public class MyTask { @Scheduled(initialDelay = 30, timeUnit = TimeUnit.MINUTES) public void work() { // this task will be executed only once, after 30 minutes } }
This task is scheduled to run only once after an initial delay of 30 minutes.
6. Configure intervals in application configuration file
The @Scheduled annotation allows us to read intervals from configuration using attributes suffixed with “String”, such as initialDelayString, fixedDelayString, and fixedRateString. For example, we can define the initial delay and fixed rate in the application.properties file as follows:
app.task.initial.delay=5 app.task.fixed.delay=45
Then use the “${…}” placeholders in the @Scheduled annotation as shown below:
public class MyTask { @Scheduled(initialDelayString = "${app.task.initial.delay}", fixedDelayString = "${app.task.fixed.delay}", timeUnit = TimeUnit.MINUTES) public void work() { // task execution logic } }
Very convenient, right? The xxxString attributes also support Spring Expression Language (SpEL) for more powerful customization.
7. Cron-like scheduling
If you’re familiar with cronjobs on Unix systems, you will find the @Scheduled annotation’s cron attribute helpful. It allows you to schedule your tasks in more sophisticated and powerful ways, such as running at 2:00 AM every weekend or at 8:15PM every Monday.
For example, the following task is scheduled to be executed at 10:15 AM every weekday (except Saturday and Sunday):
public class MyTask { @Scheduled(cron = "0 15 10 ? * MON-FRI") public void work() { // task execution logic } }
You see, this kind of scheduling cannot be configured with fixedRate or fixedDelay, so use cron attribute when you need this type of scheduling for your tasks. Check this article to learn more about cron expressions.
Conclusion:
Throughout this article, you’ve seen how the Spring framework makes it easy to implement scheduled tasks with various configurations. Note that the @Scheduled annotation requires exactly one of the cron, fixedDelay or fixedRate attributes to be specified, along with an optional initialDelay. And if only initialDelay is specified, the task will be executed only once (one-time task). I also recommend you watch the following video to see the coding in action:
References:
Comments