Scheduling Tasks in Spring Boot
Run tasks on a schedule — clean up expired tokens every hour, send daily reports, sync data every 5 minutes.
Setup
@SpringBootApplication
@EnableScheduling
public class BookstoreApiApplication { }
@Scheduled Options
@Service
public class ScheduledTasks {
// Every 5 seconds
@Scheduled(fixedRate = 5000)
public void runEvery5Seconds() {
log.info("Fixed rate task: {}", LocalDateTime.now());
}
// 10 seconds after previous execution finishes
@Scheduled(fixedDelay = 10000)
public void runWithDelay() {
log.info("Fixed delay task: {}", LocalDateTime.now());
}
// Initial delay + fixed rate
@Scheduled(initialDelay = 5000, fixedRate = 30000)
public void runAfterStartup() {
log.info("Started 5s after boot, runs every 30s");
}
// Cron expression: every day at 2:00 AM
@Scheduled(cron = "0 0 2 * * *")
public void dailyCleanup() {
log.info("Daily cleanup at 2 AM");
tokenService.deleteExpiredTokens();
}
}
| Parameter | Behavior |
|---|---|
fixedRate |
Runs at constant intervals (even if previous is still running) |
fixedDelay |
Waits for previous to finish + delay |
cron |
Unix-like cron expression |
Cron Expressions
┌───────────── second (0-59)
│ ┌───────────── minute (0-59)
│ │ ┌───────────── hour (0-23)
│ │ │ ┌───────────── day of month (1-31)
│ │ │ │ ┌───────────── month (1-12)
│ │ │ │ │ ┌───────────── day of week (0-7, 0=Sun)
│ │ │ │ │ │
* * * * * *
| Expression | Schedule |
|---|---|
0 0 * * * * |
Every hour |
0 0 2 * * * |
Daily at 2:00 AM |
0 0 9-17 * * MON-FRI |
Every hour 9 AM–5 PM weekdays |
0 */15 * * * * |
Every 15 minutes |
0 0 0 1 * * |
First day of every month |
Real-World Examples
@Service
public class BookstoreScheduler {
private final TokenRepository tokenRepository;
private final ReportService reportService;
private final CacheManager cacheManager;
// Clean expired tokens every hour
@Scheduled(cron = "0 0 * * * *")
public void cleanExpiredTokens() {
int deleted = tokenRepository.deleteExpiredBefore(Instant.now());
log.info("Cleaned {} expired tokens", deleted);
}
// Send daily sales report at 8 AM
@Scheduled(cron = "0 0 8 * * MON-FRI")
public void sendDailySalesReport() {
reportService.generateAndSendDailyReport();
}
// Warm cache every 30 minutes
@Scheduled(fixedRate = 1800000)
public void warmCache() {
cacheManager.getCache("popularBooks").clear();
bookService.getPopularBooks(); // repopulates cache
}
}
ShedLock — Distributed Locking
When running multiple instances, you don’t want the same task running on all of them:
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>5.12.0</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>5.12.0</version>
</dependency>
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "10m")
public class SchedulerConfig {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}
@Scheduled(cron = "0 0 2 * * *")
@SchedulerLock(name = "dailyCleanup", lockAtLeastFor = "5m", lockAtMostFor = "30m")
public void dailyCleanup() {
// Only ONE instance runs this — others skip
tokenService.deleteExpiredTokens();
}
Key Takeaways
@EnableScheduling+@Scheduled= background task scheduling.fixedRatefor constant intervals;fixedDelaywaits for completion.- Cron expressions for complex schedules (daily, weekdays, monthly).
- ShedLock prevents duplicate execution across multiple instances.
- Scheduled tasks should be idempotent — safe to run multiple times.
What’s Next?
Next: Application Events — decoupling components with Spring events.