Enterprise Java

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.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button