Home/Learn/Spring Boot/Scheduling with @Scheduled

Scheduling with @Scheduled

Intermediate
Advanced

@Scheduled triggers a method on a fixed rate, fixed delay, or cron expression; @EnableScheduling must be present and methods must return void.

Overview

Spring's `@Scheduled` annotation turns any `void` Spring bean method into a background task. `@EnableScheduling` (on a `@Configuration` class or the main class) activates the scheduler. Three trigger modes: **fixedRate** (fire every N ms regardless of execution time — can overlap if the task takes longer), **fixedDelay** (wait N ms after the previous execution completes — no overlap), and **cron** (UNIX-style 6-field cron expression). By default all `@Scheduled` tasks share a single-threaded `ThreadPoolTaskScheduler` — tasks queue behind each other. For concurrent tasks, configure a `TaskScheduler` bean with a larger pool size. For clustered deployments, use ShedLock or Quartz to prevent duplicate execution across pods.

fixedRate, fixedDelay, and cron

`fixedRate` fires at a fixed interval from the previous **start** time — runs overlap if execution exceeds the period. `fixedDelay` fires N ms after the previous **end** time — safe for tasks that must not overlap. `cron` is most flexible for calendar-based schedules. Use `initialDelay` to delay the first run after startup.

Spring Boot — @Scheduled fixedRate / fixedDelay / cron
@Configuration
@EnableScheduling
public class SchedulingConfig { }

@Component
public class ReportScheduler {

    // Every 30 seconds regardless of execution time (can overlap)
    @Scheduled(fixedRate = 30_000)
    public void generateMetricsSnapshot() {
        metricsService.snapshot();
    }

    // 10 seconds AFTER the last run completes (no overlap)
    @Scheduled(fixedDelay = 10_000, initialDelay = 5_000)
    public void cleanExpiredSessions() {
        sessionRepo.deleteExpired(Instant.now());
    }

    // CRON: every day at 02:30 (6-field: sec min hour day month weekday)
    @Scheduled(cron = "0 30 2 * * *")
    public void dailyEmailReport() {
        reportService.sendDaily();
    }

    // Read cron from config — allows per-environment schedule
    @Scheduled(cron = "${reports.invoice.cron:0 0 1 * * *}")
    public void invoiceRun() {
        invoiceService.processAll();
    }
}

Custom TaskScheduler for Concurrent Tasks

The default scheduler is single-threaded — a long-running task blocks all others. Provide a `TaskScheduler` bean with a named thread pool. Use `ThreadPoolTaskScheduler` for multiple tasks running concurrently, or `@Async` on individual tasks to offload them from the scheduler thread.

Spring Boot — custom TaskScheduler with thread pool
@Configuration
@EnableScheduling
public class SchedulingConfig {

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(5);                    // 5 concurrent scheduled tasks
        scheduler.setThreadNamePrefix("sched-");
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.setAwaitTerminationSeconds(30);    // graceful shutdown
        return scheduler;
    }
}

// Alternative: @Async to offload a specific task from the scheduler thread
@Scheduled(fixedDelay = 5_000)
@Async("taskExecutor")          // runs in a separate thread pool
public void heavyDataSync() {
    // Long-running — won't block other @Scheduled tasks
    dataSync.syncAll();
}

Distributed Scheduling with ShedLock

In a multi-pod Kubernetes deployment, every pod runs its own scheduler — `@Scheduled` tasks execute on all pods simultaneously. **ShedLock** uses a distributed lock (stored in a DB table, Redis, or Mongo) to ensure only one pod executes each task at a time. Annotate the method with `@SchedulerLock(name = "taskName", lockAtMostFor = "PT10M")`.

Spring Boot — ShedLock for distributed scheduling
<!-- pom.xml -->
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-spring</artifactId>
    <version>5.13.0</version>
</dependency>
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-jdbc-template</artifactId>
    <version>5.13.0</version>
</dependency>

@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "PT5M")
public class ShedLockConfig {
    @Bean
    public LockProvider lockProvider(DataSource ds) {
        return new JdbcTemplateLockProvider(
            JdbcTemplateLockProvider.Configuration.builder()
                .withJdbcTemplate(new JdbcTemplate(ds))
                .usingDbTime()
                .build());
    }
}

@Scheduled(cron = "0 0 2 * * *")
@SchedulerLock(name = "dailyReport",
               lockAtMostFor  = "PT30M",   // release lock after 30min even if node dies
               lockAtLeastFor = "PT1M")    // hold lock for min 1min (avoid double-fire on restart)
public void dailyReport() {
    reportService.generate();
}

Key Points to Remember

  • 1fixedRate: fires every N ms from last start — can overlap; fixedDelay: N ms after last end — safe
  • 2cron uses 6 fields (sec min hour day month weekday) — externalise via ${} for per-env config
  • 3Default scheduler is single-threaded — provide a ThreadPoolTaskScheduler bean for concurrency
  • 4@Async on a @Scheduled method offloads it to a separate executor thread pool
  • 5Multi-pod deployments: all pods run @Scheduled independently — use ShedLock for one-pod-only
  • 6setWaitForTasksToCompleteOnShutdown(true) ensures graceful drain on SIGTERM

Interview Questions

Sign in to ask Aria
1

What is the difference between fixedRate and fixedDelay in @Scheduled?

EasyInfosys
2

Why does the default @Scheduled setup cause problems when you have multiple tasks?

MediumAccenture
3

How would you ensure a scheduled task runs on only one pod in a Kubernetes deployment?

HardAmazon
4

How would you make a @Scheduled task's schedule configurable per environment?

EasyThoughtWorks
5

What is ShedLock and how does it prevent duplicate scheduled task execution?

MediumBooking.com

Ask Aria about Scheduling with @Scheduled

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…