Run a Spring Boot Scheduled Task Only Once – Practical Code Guide
This article explains how to configure a Spring Boot scheduled task to execute just once, covering three approaches—specifying a start time with TaskScheduler, using @Scheduled with an initial delay, and creating a custom PeriodicTrigger—complete with runnable code examples.
In this article we learn how to control a scheduled task so that it runs only once in a Spring Boot 3.2.5 application. While @Scheduled is convenient for recurring jobs, sometimes a one‑time execution is required, such as initializing resources or performing a data migration.
1. Introduction
We will explore several methods to achieve a single‑run task, ranging from using @Scheduled with an initial delay to leveraging TaskScheduler and custom triggers.
2. Practical Cases
2.1 Specify a Start Time with TaskScheduler
The @Scheduled annotation lacks flexibility for one‑time tasks. By using Spring's TaskScheduler we can programmatically schedule a Runnable to run at a specific Instant :
<code>public class TaskComponent {
private TaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
public void schedule(Runnable task, Instant startTime) {
taskScheduler.schedule(task, startTime);
}
}
</code>This method is ideal because all other TaskScheduler methods are intended for periodic execution.
Note: The example uses SimpleAsyncTaskScheduler . In Spring 6.1+ you can enable virtual threads:
<code>SimpleAsyncTaskScheduler scheduler = new SimpleAsyncTaskScheduler();
scheduler.setVirtualThreads(true);
</code>A unit test can verify the one‑time execution:
<code>@Test
public void testOnceTask() throws Exception {
CountDownLatch cdl = new CountDownLatch(1);
scheduler.schedule(() -> {
cdl.countDown();
// TODO: task action
}, Instant.now().plus(Duration.ofSeconds(1)));
cdl.await();
}
</code>2.2 Using @Scheduled with Initial Delay
Another option is to use the @Scheduled annotation with initialDelay while omitting fixedDelay or fixedRate :
<code>@Component
public class TaskComponent {
@Scheduled(initialDelay = 3000)
public void task() {
// TODO: task action
}
}
</code>This runs the task once after a 3‑second delay and does not repeat.
2.3 Custom Trigger with PeriodicTrigger
For maximum control we can implement a custom trigger by extending PeriodicTrigger and overriding nextExecution() to return null after the first execution:
<code>public class PackTrigger extends PeriodicTrigger {
public PackTrigger(Instant when) {
super(Duration.ofSeconds(1));
Duration difference = Duration.between(Instant.now(), when);
setInitialDelay(difference);
}
@Override
public Instant nextExecution(TriggerContext triggerContext) {
if (triggerContext.lastCompletion() == null) {
return super.nextExecution(triggerContext);
}
// Returning null stops further executions
return null;
}
}
</code>Using this trigger:
<code>TaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
taskScheduler.schedule(() -> {
System.out.printf("%s, executing task%n", Thread.currentThread().getName());
}, new PackTrigger(Instant.now().plusSeconds(2)));
</code>This custom trigger provides the most flexible way to ensure a scheduled task runs only once.
Below are two illustrative images from the original article:
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.