Execute Scheduled Task Only Once in Spring Boot
Usually, we configure tasks to run periodically. However, there are situations where we may need to schedule a task to execute just once at a specified future time, such as for resource initialization or data migration. Let us delve into understanding how Spring Boot can execute a scheduled task only once.
1. Introduction
In a Spring Boot application, there may be scenarios where you need a task to execute just once after the application starts or at a specific time. Unlike the traditional @Scheduled
annotation, which can trigger repeated executions based on a cron or fixed rate, we want to run the task only one time without recurring.
2. Code Example
Let’s explore the different methods for executing one-time scheduled tasks in Spring Boot.
2.1 Setting up the Project
We’ll start by creating a Spring Boot project with the help of Spring Initializr and add the necessary dependencies. In the pom.xml
file, add the following dependencies:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId></groupId> <artifactId>spring-boot-starter-scheduling</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
2.2 Main Application Class
The SingleExecutionApplication.java
is the entry point to your Spring Boot application:
package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SingleExecutionApplication { public static void main(String[] args) { SpringApplication.run(SingleExecutionApplication.class, args); } }
2.3 Task Scheduler Config with Start-Time Only
In this example, we use TaskScheduler
to schedule a task to run only once after a delay (5 seconds). The task will execute once at the specified time and will not repeat.
package com.example.config; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import java.util.Date; @Configuration public class OneTimeTaskSchedulerConfig { @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(1); return scheduler; } @Bean public CommandLineRunner scheduleTask(TaskScheduler taskScheduler) { return args -> { Date startTime = new Date(System.currentTimeMillis() + 5000); // 5 seconds delay taskScheduler.schedule(() -> { System.out.println("Executing task once at " + new Date()); }, startTime); }; } }
2.3.1 Code Explanation
The provided code is a Spring Boot configuration class that sets up a one-time scheduled task. In this code, the @Configuration
annotation indicates that the class contains Spring configuration settings. The OneTimeTaskSchedulerConfig
class defines two beans: taskScheduler
and scheduleTask
.
The taskScheduler
bean is created using the ThreadPoolTaskScheduler
, which is a Spring utility that allows for scheduling tasks in a multi-threaded environment. The pool size is set to 1, meaning that only one thread will be used for executing scheduled tasks.
The second bean, scheduleTask
, is defined as a CommandLineRunner
. This interface allows you to execute code after the Spring application context has been initialized. Within this method, a delay of 5 seconds is set before executing the task. The schedule
method of the TaskScheduler
is then called to schedule a task that prints a message to the console indicating that the task is being executed, along with the current date and time.
2.4 Using @Scheduled with Initial Delay Only
The @Scheduled
annotation in Spring is used to schedule tasks to run at fixed intervals, specific times, or after a certain delay. By adding @Scheduled
to a method, you can configure it to execute automatically based on parameters like fixedRate
, fixedDelay
, cron
, and initialDelay
. For example, fixedRate
runs the task at a constant interval, regardless of when the previous execution finished, while fixedDelay
waits a specified period after the last execution finishes before running again. The cron
parameter allows for more complex scheduling patterns using cron expressions, specifying exact timings, like every day at a particular hour or specific days of the week. Additionally, initialDelay
can be set to delay the first execution after the application starts. This flexibility makes @Scheduled
ideal for automating repetitive tasks, such as data cleanup, report generation, or background jobs within a Spring application.
In this approach, we use @Scheduled
to execute the task once after a delay of 5 seconds. The isExecuted
flag ensures the task is only executed once.
package com.example.config; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class OneTimeScheduledTask { private boolean isExecuted = false; @Scheduled(initialDelay = 5000) // Run 5 seconds after application starts public void runOnceTask() { if (!isExecuted) { System.out.println("Executing one-time task with @Scheduled"); isExecuted = true; // Prevent future executions } } }
2.4.1 Code Explanation
The provided code defines a Spring component named OneTimeScheduledTask
. This class is responsible for executing a one-time scheduled task using the @Scheduled
annotation.
Within the class, there is a private boolean variable isExecuted
that is initialized to false
. This variable is used to track whether the task has already been executed.
The @Scheduled
annotation is used to specify that the method runOnceTask
should be executed after an initial delay of 5 seconds from when the application starts.
Inside the runOnceTask
method, there is a check to see if isExecuted
is still false
. If it is, the method prints a message indicating that the one-time task is being executed and sets isExecuted
to true
. This prevents the task from being executed again in future invocations, ensuring that it runs only once.
2.5 Using PeriodicTrigger Without a Next Execution
This approach uses a PeriodicTrigger
to schedule the task to run only once. We cancel the task after its execution.
package com.example.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.PeriodicTrigger; import java.util.concurrent.ScheduledFuture; @Configuration public class SingleExecutionConfig { @Autowired private TaskScheduler taskScheduler; private ScheduledFuture<?> scheduledFuture; @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(1); return scheduler; } @Bean public CommandLineRunner runOneTimeTask() { return args -> { Trigger singleExecutionTrigger = new PeriodicTrigger(0); // Trigger once immediately scheduledFuture = taskScheduler.schedule(() -> { System.out.println("Executing task once with PeriodicTrigger"); scheduledFuture.cancel(false); // Cancel the task after execution }, singleExecutionTrigger); }; } }
2.5.1 Code Explanation
The provided code defines a Spring configuration class named SingleExecutionConfig
, which is designed to set up a one-time task execution using a TaskScheduler
.
The class is annotated with @Configuration
, indicating that it contains Spring bean definitions. Within this class, the TaskScheduler
is automatically injected using the @Autowired
annotation, allowing the class to utilize Spring’s scheduling capabilities.
A private variable scheduledFuture
of type ScheduledFuture<?>
is declared to hold the reference to the scheduled task, which can be used later to manage its execution.
The first bean method, taskScheduler
, creates a new instance of ThreadPoolTaskScheduler
. This scheduler is configured with a pool size of 1, meaning it can execute one task at a time.
The second bean method, runOneTimeTask
, returns a CommandLineRunner
. This interface allows the specified code to be executed once the Spring application context has been initialized. Inside this method, a PeriodicTrigger
is created with a period of 0 milliseconds, which means it will trigger immediately.
The task is scheduled using the taskScheduler.schedule()
method. The scheduled task prints a message indicating that it is being executed and then cancels itself by calling scheduledFuture.cancel(false)
. This ensures that the task runs only once and does not continue to execute in the future.
2.6 Run the application
Run the code by running the SingleExecutionApplication.java
and the below logs will be logged on the IDE console.
Executing task once at Thu Nov 07 16:00:10 IST 2024 Executing one-time task with @Scheduled Executing task once with PeriodicTrigger
3. Conclusion
This systematic Spring Boot application demonstrates multiple ways to execute a task only once, using the TaskScheduler
, @Scheduled
annotation with an initial delay, and PeriodicTrigger
to cancel the task after its first execution. This provides flexibility to suit various use cases where one-time task execution is required.