In this tutorials of Spring Boot, we will look at the Spring boot scheduler. We will see how to schedule tasks with Spring Boot. During this post, let’s look at the Spring @Scheduled annotation.
Introudction
Spring Boot use the @Scheduled annotation to schedule tasks. It internally use the TaskScheduler
interface for scheduling the annotated methods for execution. While using this annotation, we may need to follow certain rules:
- Methos should not accept any parameters.
- Return type for the method should be void.
1. Project Setup.
Let’s create a simple application for our Spring boot scheduler. We have the following options to create a Spring Boot project.
This is how our pom.xml
look like:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.javadevjournal</groupId>
<artifactId>spring-boot-scheduler</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-scheduler</name>
<description>Spring Boot schedule sample application</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. Enable Scheduling
T0 enable the scheduling; we need to add the @EnableScheduling
annotation. We have the following 2 options to add this annotation in our application:
- Add the
@EnableScheduling
annotation to the main class. - Annotate the configuration class with this annotation.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SpringBootSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSchedulerApplication.class, args);
}
}
[pullquote align=”normal”]The @EnableScheduling
annotation creates a background task executor. [/pullquote]
3. Scheduling Tasks
The main work for any scheduler is to schedule the tasks. Spring Boot make it easy to create a scheduling task. We only need to annotate the method with the @Scheduled
annotation. Let’s look at one of the example for a better understanding:
@Component
public class SayHelloTask {
private static final Logger LOG = LoggerFactory.getLogger(SayHelloTask.class);
@Scheduled(fixedRate = 1000)
public void sayHello(){
LOG.info("Hello from our simple scheduled method");
}
}
Let’s look at some important points:
- The
@Scheduled
annotation defines the scheduling (e.g. when method will run etc.) - We can pass some parameters to the annotation for customize the behaviour.
If we run this application, you will see the following output in the console after application startup:
2019-10-10 20:53:12.447 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:13.448 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:14.446 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:15.450 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:16.448 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:17.446 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
In the next section, we will look at some parameter which can be used with the Scheduled
annotation.
4. Tasks with Fixed Rate
To schedule a method trigger at a fixed internal, we can use the fixedRate
parameter in the @Scheduled
annotation. Let’s take an example, where we want to execute method every 1 seconds:
@Scheduled(fixedRate = 1000)
public void sayHello(){
LOG.info("Hello from our simple scheduled method");
}
5. Scheduling with Fixed Delay
Let’s say we want a fixed delay between the last execution and start of next execution. We can use the fixedDelay
parameter in this annotation. This parameter counts the delay after the completion of the last invocation.
@Scheduled(fixedDelay = 2000)
public void fixedDelayExample(){
LOG.info("Hello from our Fixed delay method");
}
This is how the output is look like:
2019-10-10 21:19:38.331 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:19:40.333 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:19:42.345 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:19:44.346 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
Here, the tasks getting triggered with the delay of 2 seconds. Let’s add some change to our method for a better understanding. Let’s assume that, our tasks takes 3 minutes to complete, in this case, next execution should start in 5 seconds (3 seconds for completion and 2 seconds delay).
@Scheduled(fixedDelay = 2000)
public void fixedDelayExample() {
LOG.info("Hello from our Fixed delay method");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ie) {
LOG.error("Got Interrupted {}", ie);
}
}
When we run this code, we will have following output:
2019-10-10 21:25:11.623 INFO 46242 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:25:16.629 INFO 46242 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:25:21.633 INFO 46242 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
Total delay of 5 seconds.
5.1. Parallel Scheduling
We can also enable parallel scheduling by adding the @Async annotation to the scheduled tasks. Let’s look at this example:
@EnableAsync
public class ParallelSchedulingExample {
@Async
@Scheduled(fixedDelay = 2000)
public void fixedDelayExample() {
LOG.info("Hello from our Fixed delay method");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ie) {
LOG.error("Got Interrupted {}", ie);
}
}
}
6. Schedule a Task with Initial Delay
We can also use the initialDelay
parameter to delay the first execution of the task with the specified number of milliseconds.We can combine this parameter with fixedRate
and fixedDelay
based on our requirements.
@Scheduled(fixedRate = 2000, initialDelay = 5000)
public void scheduleTaskWithInitialDelay() {
LOG.info("Fixed Rate Task with Initial Delay");
}
@Scheduled(fixedRate = 2000, fixedDelay = 5000)
public void scheduleTaskWithInitialDelay() {
LOG.info("Fixed Rate Task with Initial Delay");
}
When we run our application, we will have following output:
2019-10-10 21:58:01.415 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
2019-10-10 21:58:03.412 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
2019-10-10 21:58:05.417 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
2019-10-10 21:58:07.415 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
7. Cron Expression
Cron expression is a flexible and powerful way to schedule the tasks. The pattern is a list of six single space-separated fields: representing second, minute, hour, day, month, weekday. Month and weekday names can be given as the first three letters of the English names. In this example, we are scheduling the tasks for every 1 minute using cron expression:
@Scheduled(cron = "0 * * * * ?")
public void scheduleTaskWithCronExpression() {
LOG.info("Example to show how cron expression can be used");
}
When we run our application, it will execute the tasks in every 1 minute. This is how the output look like:
2019-10-12 19:25:00.003 INFO 74830 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Example to show how cron expression can be used
2019-10-12 19:26:00.003 INFO 74830 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Example to show how cron expression can be used
8. Parametrising the Schedule
Spring Boot and Spring provides a powerful mechanism to externalize your configuration using the properties file. While working on any enterprise applications, It’s always good practice to externalize the configuration to avoid hard coding. It also helps in following aspects
- Ability to change the configurations without redeploy.
- System do not need any re-compile for property changes.
Let’s use the Spring expression language to externalize the schedule expressions through property file.This is how the new code look like:
@Scheduled($ {
fixedrate.value
})
public void sayHello() {
LOG.info("Hello from our simple scheduled method");
}
@Scheduled($ {
fixeddelay.value
})
public void fixedDelayExample() {
LOG.info("Hello from our Fixed delay method");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ie) {
LOG.error("Got Interrupted {}", ie);
}
}
@Scheduled($ {
cron.expression
})
public void scheduleTaskWithCronExpression() {
LOG.info("Example to show how cron expression can be used");
}
9. Custom Thread Pool
The @Scheduled
annotation will execute the tasks in the default thread pool.Spring creates the default thread pool of the size 1 during the startup.Let’s run our previous examples to verify this statement:
2019-10-13 11:23:13.224 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:14.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:15.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:16.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:17.224 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:18.221 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:19.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
We added the following line in the log to print thread name: Thread.currentThread().getName()
. Spring provides the flexibility to create custom thread pool and execute all the tasks using the custom thread pool. Let’s see how we can create and configure custom thread pool for our application.
@Configuration
public class CustomThreadPoolConfig implements SchedulingConfigurer {
private final int CUSTOM_POOL_SIZE = 5;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(CUSTOM_POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("javadevjournal");
threadPoolTaskScheduler.initialize();
//let's register our custom thread pool scheduler
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
Now when we run our application, Spring will use the new thread pool.This is how the output look like:
2019-10-13 11:32:54.570 INFO 88821 --- [javadevjournal1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal1
2019-10-13 11:32:55.571 INFO 88821 --- [javadevjournal2] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal2
2019-10-13 11:32:56.571 INFO 88821 --- [javadevjournal1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal1
2019-10-13 11:32:57.571 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:32:58.572 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:32:59.571 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:33:00.569 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:33:01.572 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3</code?
[pullquote align=”normal”] Spring scheduling is a good alternate for simple use cases but if you are looking for more advance scheduling framework (like persistence etc.), consider using Quartz scheduler. [/pullquote]
Summary
In this post, we looked at the Spring boot scheduler. we understood the way to configure and use the @Scheduled annotation. We saw different option to customize the @Scheduled
annotation by passing different parameters. In the end of this post, we saw how to configure custom thread pool for our application. The source code for this post is available on the GitHub
Can you please explain How to get status of a task from default Scheduler? I want to schedule few task and monitor it which ome is running currently and finished ? Thank you.
Not clear what you are looking for? Are you talking about getting status for your scheduled jobs?