Chapter 06

スケジュール機能を使ってみよう編

すがりょー
すがりょー
2021.03.06に更新

突然なんですが、ぼくはかなりの ツイ廃 でして。

こんなツイートを機械的にしています。

これ is 何?

以前、趣味で作ったツールをSpringBootでリライトしたものがあり、それに 時報モドキ の機能があります。
こんな感じで #にゃっぴこーる というタグを付けて、毎時ちょうどに時報をぶっ放しています。
ちなみに、たまに時報以外に切り替えて 別なことをツイートする ので、時報 モドキ となっています。
まぁそれは置いといて。

この時報ツイートは @Scheduled という SpringBootのスケジュール機能 を使っています。

■スケジュール機能を有効化してみよう

スケジュール機能を利用するには、裏でタイマーを走らせる必要があるので明示的に 機能の有効化 が必要になります。

と言っても別に難しい実装が必要なわけじゃなく、ぶっちゃけ アノテーション1個付けるだけ です。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

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

こんな感じで @EnableScheduling でアノテートすると、スケジュール機能を使えるようになります。

確かこの有効化アノテーションを付けるのはアプリケーション配下の (スキャン範囲に入っていれば) どこでも良いらしいんですが。
この手の有効化アノテーションは一箇所に纏まってたほうが解り易い (管理しやすい) と思うので、ぼくはいつも @SpringBootApplication をアノテートしているアプリケーションクラスに纏めて付けています。

同様の有効化アノテーションの例として、非同期処理を行う @Async を使うための @EnableAsync などがあります。

■スケジュール機能を使ってみよう

これでスケジュール機能を利用する準備が整いました。
ということで早速、スケジュール機能を使ってみましょう。

適当な @RestController や任意の @Component クラスを作って、定期的に実行したいメソッドに @Scheduled アノテーションを付与します。

これはもうサンプルコードを見た方が圧倒的に理解が早いと思うので、さっさと参考実装を見てみましょう。

スケジューラの参考実装
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class NyappiScheduler {

    @Autowired
    NyappiCall nyappi;

    @Scheduled(cron = "${schedule.nyappi_call.cron}")
    public void cron() {
        this.nyappi.randomcall();
    }
}
application.properties
schedule.nyappi_call.cron=0 0 * * * *

Spring大先生のアノテーションは 神機能 であらせられるので、外部定義ファイルの設定値でアノテート出来ます。

上記参考実装の場合、外部定義ファイルの schedule.nyappi_call.cron に設定している 0 0 * * * * という cronライクな記法 に従って定期実行されます。
つまりこの場合は 「毎時0分0秒に実行しなさい」 ということですね。

なお、@Scheduled アノテーションに指定できるのはcron記法だけではなく、以下のようなパラメータを指定できます。

  • cron系
    • cron
      • second
      • minute
      • hour
      • day of month
      • month
      • day of week
    • zone
  • 一定間隔系
    • initialDelay
    • fixedRate
    • fixedDelay
    • initialDelayString
    • fixedRateString
    • fixedDelayString

> cron系

参考実装で示した通り、cronライクな記法で 実行スケジュールを曜日月日時分秒で指定 するパターンです。

> 一定間隔系

一定間隔系は大きく 2種類 に別れます。

  • fixedRate 一定周期でタスク実行
  • fixedDelay 一定間隔でタスク実行

どう違うねん!!

どちらも一定のスパンでタスク実行される点では同じですが、その 判定基準 が異なります。

  • fixedRate 前回タスク開始 を基準に次のタスクを実行。
  • fixedDelay 前回タスク終了 を基準に次のタスクを実行。

つまり 「タスクとタスクの間隔が一定;fixedDelay」 なのか、 「タスク毎の開始間隔が一定;fixedRate」 なのか、ということですね。

  • initialDelay

initialDelayfixedRate/fixedDelay に付属するオプションみたいなもので、 アプリケーションをデプロイしてから初回実行までの間隔 を指定します。

■スケジュール(定期実行タスク)機能に関する余談

実際のシステム開発に於いては スケジュール(定期実行タスク) を実装する上では以下の選択になるかと思います。

  • @Scheduled アノテーション使って内部的にスケジューラをを回す。
  • エンドポイントだけ公開しといて、外部で cron を回して curl 叩く。
個人的には・・・

個人的には、後者 の方がスケジュールのハンドリングや管理のしやすさという意味で良いかなと思ってます。
基本的に、実務でのシステム開発ではほぼ後者を選択する事になるかなと思います。
よくあるケースとして運用部門の JP1 とか SystemWalker とかの方が主導権握ってて、そっちからキックするのが既定路線だったりしますしね。

趣味ツールに於いても、定期実行した結果をファイルに蓄積して、、、みたいな、いわゆるクローラ的な事をやる上でも後者の方が好都合ですし。

特にそういうバッチ処理的な色合いがなく、シンプルに 定期的にアクションを起こしたいだけ みたいな時に手軽に実装出来るのが @Scheduled アノテーションのいい所ですね。
外部にキックする「頭脳」を作らず、一人で勝手に動いてくれるのでラクに実装できるのがメリットですかね。
つまり、、、実務ではあまり使わない可能性が微レ存・・・?

あと、実際には @Scheduled だけで事足りる事はなく @Async でワーカースレッドと組み合わせるとか、実務ではかなり複雑になって来る所かと思います。

★スケジューラ関連の参考ページ★

ついでなんで趣味ツールのGitHubリポジトリも参考実装として載せときます。