SoFunction
Updated on 2025-04-07

SpringBoot integrated ShedLock to implement distributed timing tasks

1.What is ShedLock?

ShedLockIt is a Java library, usually used in distributed systems, ensuring that scheduled tasks (Scheduled Tasks) are executed only once by a certain instance in a cluster environment. It avoids multiple instances performing the same task at the same time by adding locks in shared resources such as databases or distributed caches

How ShedLock works

  • Distributed lock
    • At the beginning of the task, ShedLock tries to create a lock in the database (or other storage).
    • If an instance successfully acquires the lock, only it can perform the task.
  • The life cycle of lock
    • The lock will have a clear expiration time (the lock is held,lockAtLeastForandlockAtMostForparameter configuration).
    • After the lock expires, other instances can reacquire the lock even if the task terminates abnormally.
  • Supported storage
    • Supports a variety of lock storage, including databases (such as MySQL, PostgreSQL), Redis, MongoDB, etc.

Application scenarios

1. Distributed timing task control

  • In a distributed environment, multiple instances schedule timing tasks at the same time. If there is no control, it may cause repeated execution of tasks. ShedLock ensures that only one instance can run the task.
  • For example:
    • The timing task for generating daily reports.
    • A batch task to clean up expired data.

2. Avoid repeated task execution

  • Even in a single instance environment, ShedLock can be used to avoid multiple triggers of the same task due to unexpected restarts or configuration errors.

3. Idepotency of event-driven tasks

  • When certain tasks require processing of the same event, using ShedLock ensures that an event is processed only once.

4. Task retry mechanism

  • If a task needs to be retryed (for example, in the event of an error), ShedLock prevents multiple instances from retrying the same task at the same time.

2. Code Engineering

Purpose of experiment

Use ShedLock to ensure that only one instance can run the task in a distributed environment

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0"
         xmlns:xsi="http:///2001/XMLSchema-instance"
         xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
    <parent>
        <groupId></groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.1</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>shedlock</artifactId>

    <properties>
        <>17</>
        <>17</>
    </properties>
    <dependencies>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId>shedlock-spring</artifactId>
            <version>5.5.0</version>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId>shedlock-provider-jdbc-template</artifactId>
            <version>5.5.0</version>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
    </dependencies>
</project>

config

package ;

import ;
import ;
import ;
import ;
import ;

import ;

@Configuration
public class ShedLockConfig {

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(
            ()
                .withJdbcTemplate(new JdbcTemplate(dataSource))
                .usingDbTime() // Works with PostgreSQL, MySQL, MariaDb, MS SQL, Oracle, HSQL, H2, DB2, and others
                .build()
        );
    }
}

cron

package ;

import ;
import ;
import ;
import ;
import ;

@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SchedulerConfig {

    @Scheduled(cron = "0 0/1 * * * ?")
    @SchedulerLock(name = "scheduledTaskName", lockAtMostFor = "PT10M", lockAtLeastFor = "PT1M")
    public void scheduledTask() {
        //  some logic code
        ("Executing scheduled task");
    }

}
  • @Scheduled(cron = "0 0/1 * * * ?")
    • Defines the scheduled time of the timing task.
    • Expression meaning: The task triggers every minute of the entire point, such as 12:00, 12:01, 12:02.
    • Notice: Multiple instances (distributed environments) will be scheduled to this task at the same time, but through ShedLock, it ensures that only one instance can be truly executed.
  • @SchedulerLock
    • Use ShedLock to manage distributed locks.
    • name = "scheduledTaskName":
      • Defines the unique identifier of the lock. The status of this lock is recorded in shared storage such as databases or Redis.
    • lockAtMostFor = "PT10M":
      • The maximum holding time of the lock is10 minutes
      • If the task runs for more than 10 minutes, it will automatically expire even if the lock is not released actively, and other instances can continue to acquire the lock.
    • lockAtLeastFor = "PT1M":
      • The minimum holding time for the lock is1 minute
      • Even if the task is completed ahead of time, the lock will still be held for at least 1 minute, preventing other instances from repeating tasks quickly.
  • Task logic
    • ("Executing scheduled task");It is the business logic of the task.
    • This logic will only be executed on the instance where the lock is acquired.

Configuration File

node1 node

=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
=root
=123456
-class-name=
=8081

node2 node

=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
=root
=123456
-class-name=
=8082

The above are just some key codes.

3. Test

Start node1

java -jar  --=node1

Start node2 node

java -jar  --=node2

Observing the logs through the console, you can find that two instances acquire lock execution alternately, rather than execution at the same time together

4. Things to note

  • Task time control: Ensure that the actual execution time of the task is less thanlockAtMostFor, otherwise the task may be repeatedly executed by other instances.
  • Idepotency: Task logic should be designed as idempotent as possible (repeated execution will not cause side effects) to cope with potential abnormalities in the lock mechanism.
  • Storage configuration: Ensure that highly available lock storage (such as database or Redis) is used, otherwise the lock mechanism may fail.

The above is the detailed content of SpringBoot integrated ShedLock to implement distributed timing tasks. For more information about SpringBoot ShedLock timing tasks, please pay attention to my other related articles!