1. 概要

Spring provides an easy way to implement API for scheduling jobs. It works great until we deploy multiple instances of our application.

Spring, by default, cannot handle scheduler synchronization over multiple instances. It executes the jobs simultaneously on every node instead.

In this short tutorial, we’ll look at ShedLock — a Java library that makes sure our scheduled tasks run only once at the same time and is an alternative to Quartz.

2. Mavenの依存関係

SpringでShedLockを使用するには、shedlock-spring依存関係を追加する必要があります。

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

3. 構成

ShedLockは、適切なLockProviderを宣言することにより、共有データベースがある環境でのみ機能することに注意してください。データベースにテーブルまたはドキュメントを作成し、現在のロックに関する情報を格納します。

Currently, ShedLock supports Mongo, Redis, Hazelcast, ZooKeeper and anything with a JDBC driver.

For this example, we’ll use an in-memory H2 database.

To make it work, we need to provide the H2 database and the ShedLock JDBC dependency:

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

次に、スケジューラロックに関する情報を保持するために、ShedLockのデータベーステーブルを作成する必要があります。

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

We should declare the data source in our Spring Boot application’s properties file so that the DataSource bean can be Autowired.

Here we use the application.yml to define the data source of the H2 database:

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:

Let’s config the LockProvider with the data source configuration above.

春はそれをかなり簡単にすることができます:

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

Other configuration requirements we have to provide are the @EnableScheduling and @EnableSchedulerLock annotations on our Spring configuration class:

@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringApplication.class, args);
    }
}

defaultLockAtMostFor パラメーターは、実行中のノードが停止した場合にロックを保持するデフォルトの時間を指定します。 ISO8601期間形式を使用します。

次のセクションでは、このデフォルトをオーバーライドする方法を説明します。

4. タスクの作成

ShedLockによって処理されるスケジュールされたタスクを作成するには、メソッドに@Scheduledおよび@SchedulerLockアノテーションを配置するだけです。

@Component
class BaeldungTaskScheduler {

    @Scheduled(cron = "0 0/15 * * * ?")
    @SchedulerLock(name = "TaskScheduler_scheduledTask", 
      lockAtLeastForString = "PT5M", lockAtMostForString = "PT14M")
    public void scheduledTask() {
        // ...
    }
}

まず、@Scheduledを見てみましょう。 It supports the cron format, with this expression meaning “every 15 minutes.”

Next, taking a look at @SchedulerLock, the name parameter has to be unique, and ClassName_methodName is typically enough to achieve that. このメソッドの複数の実行が同時に発生することは望ましくありません。ShedLockは一意の名前を使用してそれを実現します。

また、いくつかのオプションのパラメーターを追加しました。

First, we added lockAtLeastForString so that we can put some distance between method invocations. Using “PT5M” means that this method will hold the lock for five minutes, at a minimum. つまり、は、このメソッドをShedLockで実行できる頻度が5分ごとであることを意味します。

次に、 lockAtMostForString を追加して、実行中のノードが停止した場合にロックを保持する期間を指定しました。 「PT14M」を使用すると、14分以内にロックされます。

通常の状況では、ShedLockはタスクが終了した直後にロックを解放します。 Now, we didn’t have to do that because there is a default provided in @EnableSchedulerLock, but we’ve chosen to override that here.

5. 結論

In this article, we learned how to create and synchronize scheduled tasks using ShedLock.

いつものように、すべてのソースコードはGitHub利用できます。