How to Ensure Spring Boot Scheduled Tasks Run Only Once with ShedLock

Learn how to prevent duplicate execution of Spring Boot @Scheduled tasks in multi-instance deployments by integrating ShedLock, including Maven dependencies, H2 database setup, LockProvider configuration, and annotation usage to ensure each job runs only once across all nodes.

Programmer DD
Programmer DD
Programmer DD
How to Ensure Spring Boot Scheduled Tasks Run Only Once with ShedLock

In previous Spring Boot tutorials we introduced the @Scheduled annotation for creating scheduled tasks, but when deploying multiple instances the same task runs on every node, causing duplicate execution because Spring does not synchronize scheduling across instances by default.

This article explains how to use ShedLock so that a scheduled task runs only once at a time in a multi-instance environment, and it can also serve as an alternative to Quartz.

Maven Dependency

First add the shedlock-spring dependency:

<dependency>
  <groupId>net.javacrumbs.shedlock</groupId>
  <artifactId>shedlock-spring</artifactId>
  <version>6.3.1</version>
</dependency>

The latest version can be found on Maven Central.

Configuration

ShedLock requires a shared database and a suitable LockProvider. It creates a table/document to store the current lock. It supports Mongo, Couchbase, Elasticsearch, Redis, Hazelcast, ZooKeeper, Cassandra, and any JDBC‑compatible database. The example uses an in‑memory H2 database for simplicity.

Add the following dependencies for H2 and the JDBC‑based ShedLock provider:

<dependency>
  <groupId>net.javacrumbs.shedlock</groupId>
  <artifactId>shedlock-provider-jdbc-template</artifactId>
  <version>6.3.1</version>
</dependency>
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>2.1.214</version>
</dependency>

Create a table to store locks:

CREATE TABLE shedlock (
  name VARCHAR(64),
  lock_until TIMESTAMP(3) NULL,
  locked_at TIMESTAMP(3) NULL,
  locked_by VARCHAR(255),
  PRIMARY KEY (name)
)

Configure the datasource in application.yml so that Spring can inject it:

spring:
  datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:shedlock_DB;INIT=CREATE SCHEMA IF NOT EXISTS shedlock;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:

Define a LockProvider bean that uses the datasource:

@Configuration
public class SchedulerConfiguration {
  @Bean
  public LockProvider lockProvider(DataSource dataSource) {
    return new JdbcTemplateLockProvider(dataSource);
  }
}

Enable scheduling and ShedLock in the main application class:

@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SpringBootShedlockApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootShedlockApplication.class, args);
  }
}

The defaultLockAtMostFor attribute defines how long a lock is kept when the executing node crashes, using an ISO‑8601 duration format.

Creating a Task

Make ShedLock manage a scheduled task by annotating the method with both @Scheduled and @SchedulerLock:

@Component
class BaeldungTaskScheduler {
  @Scheduled(cron = "0 0/15 * * * ?")
  @SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtLeastFor = "PT5M", lockAtMostFor = "PT14M")
  public void scheduledTask() {
    // ...
  }
}
@Scheduled

supports cron expressions; the example runs every 15 minutes. @SchedulerLock requires a unique name (typically className_methodName ) to prevent concurrent execution. Two optional parameters can be set: lockAtLeastFor guarantees a minimum lock duration, ensuring a gap between executions (e.g., PT5M means at least 5 minutes). lockAtMostFor defines the maximum time a lock is retained if the node fails (e.g., PT14M means up to 14 minutes).

Normally the lock is released as soon as the task finishes; the defaults in @EnableSchedulerLock are sufficient, but the example shows how to override them at the method level.

Summary

In short, using ShedLock allows Spring Boot applications deployed on multiple instances to ensure scheduled jobs run reliably only once.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring Bootdistributed lockscheduled tasksShedLock
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.