TES Blog

株式会社テクニカルエンジニアリングサポートに所属する社員が、自身が携わるテクノロジーやイベントに関する情報を発信しています。

Kotlin + Spring Boot + Heroku でタスクの定期実行を実装する

📌 はじめに

Spring Boot でタスクを定期実行させるやり方はたくさん公開されていますが、 Kotlin でっていう記事はあまり見受けられなかったので公開することにしました。
ただし、 Java で実装する時とほとんど何も変わりません🙄

Kotlinの勉強がてらに何か作りたいって時にはちょうど良いかもしれません!

今回は Heroku で本番公開するところまでやってみようと思います。

📌 前提条件(環境情報)

対象 バージョン
macOS Sierra 10.12.6
Java 1.8.0_121
Kotlin 1.2.71
Spring Boot 2.1.1.RELEASE

📌 実際に作る

ではさっそく、 Kotlin + Spring Boot でタスクの定期実行を実装していきます。

1. SPRING INITIALIZR で Project 作成

まずは Spring Boot のプロジェクトフォルダを作成します。

SPRING INITIALIZR にアクセスし、画面上側にあるプルダウンを以下のように選択します。

Generate a [Gradle Project] with [Kotlin] and Spring Boot [2.1.1]

次に、 Project Metadata を設定します。
ここは自由に命名してもらってかまいません。

Group Artifact
生成されるソースのパッケージ名。 アプリケーションの名前。ディレクトリ名に使われる。

最後に、 Dependencies (依存ライブラリ)を設定します。
検索ワードを入力すると、依存ライブラリの候補が表示されるので、以下のものを選択します。

検索ワード 選択項目 何に使うか
cloud task Cloud Task タスクの定期実行

こんな感じになっていればOKです。 f:id:h-marei:20181203111108p:plain

上記内容の設定がすべて終わったら、「Generate Project」ボタンでプロジェクトフォルダをzipファイルでダウンロードします。
zipファイルを解凍してお好みのディレクトリに配置してください。

2. アプリケーションクラスをタスクの定期実行(スケジューリング)に対応させる

main の処理があるアプリケーションクラスで、タスクの定期実行をするための準備を行います。
EnableScheduling をインポートし、クラスにアノテーションを追加します。

/src/main/kotlin/com/marei/springbootkotlinbatch/SpringbootKotlinBatchApplication.kt

package com.marei.springbootkotlinbatch

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.scheduling.annotation.EnableScheduling // ← 追加

@SpringBootApplication
@EnableScheduling // ← 追加
class SpringbootKotlinBatchApplication

fun main(args: Array<String>) {
    runApplication<SpringbootKotlinBatchApplication>(*args)
}

こちらのアノテーションを追加することで、後に実装するタスクが実行されるようになります。

3. タスク処理を実装する

実際に実行したいタスク処理を記述するクラスを作成します。
※クラス名は何でも良い

/src/main/kotlin/com/marei/springbootkotlinbatch/BatchTasks.kt

package com.marei.springbootkotlinbatch

import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component

@Component
class BatchTasks {
    // initialDelay:アプリケーションが起動してから何秒後に実行するか(ミリ秒指定)
    // fixedDelay:何秒ごとに処理を実行するか(ミリ秒指定)
    // アプリケーション起動5秒後と10秒間隔で実行
    @Scheduled(initialDelay = 5000, fixedDelay = 10000)
    fun helloWorld() {
        println("はろー、わーるど!")
    }

    // cron:cron 記法で実行時間を指定
    // zone:cron の起動時間のタイムゾーンを指定
    // 毎日00時00分00秒に実行
    @Scheduled(cron = "0 0 0 * * *", zone = "Asia/Tokyo")
    fun helloWorld2() {
        println("はろー、わーるど!2")
    }
}

@Scheduled アノテーションを付けたメソッドが、実際にタスクとして実行されるメソッドになります。
本記事での詳細な説明は省略しますが、こちらの記事が大変参考になります。

qiita.com

4. 動作確認

ここまで実装すれば、もうタスクを定期実行する準備は整いました。
それでは、アプリケーションを起動して動作を確認してみましょう!

アプリケーションのディレクトリ配下で下記を実行します。

./gradlew bootRun

すると、下記のようになり、「はろー、わーるど!」と表示されれば成功です🎉
※初回はインストールが実行されるので少し時間がかかります。

$ ./gradlew bootRun

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)

2018-12-03 16:03:39.096  INFO 62374 --- [           main] c.m.s.SpringbootKotlinBatchApplicationKt : Starting SpringbootKotlinBatchApplicationKt on TESPC-084.local with PID 62374 (/Users/r-hashimoto/project/private/springboot-kotlin-batch/build/classes/kotlin/main started by r-hashimoto in /Users/r-hashimoto/project/private/springboot-kotlin-batch)
2018-12-03 16:03:39.102  INFO 62374 --- [           main] c.m.s.SpringbootKotlinBatchApplicationKt : No active profile set, falling back to default profiles: default
2018-12-03 16:03:41.464  INFO 62374 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'taskScheduler'
2018-12-03 16:03:41.910  INFO 62374 --- [           main] c.m.s.SpringbootKotlinBatchApplicationKt : Started SpringbootKotlinBatchApplicationKt in 3.574 seconds (JVM running for 4.495)
はろー、わーるど!
はろー、わーるど!
はろー、わーるど!
<==========---> 80% EXECUTING [34s]
> :bootRun

※ Ctrl + C で停止

📌 Heroku で公開する

ひたすら「はろー、わーるど!」を出力するだけのタスクですが、 Heroku を利用して本番環境にデプロイしてみましょう。

jp.heroku.com (え、てか、いつの間にか日本語対応してるじゃんやば、感動😭)

1. Git の管理下にする

Heroku にデプロイする際にブランチ単位でデプロイすることになります。
※こちらの作業は Git がインストールされている前提です。

まずは、 Git の管理下にします。

git init

実装した内容をステージングに上げます。

git add .

コミットします。

git commit -m "Kotlin + Spring Boot でタスクの定期実行"

これで デプロイする用の master ブランチが完成しました。

2. Heroku CLI をインストールする

私は Mac 環境なので brew でインストールしますが、別の方法もあるので公式サイトを参考にしてください。

brew install heroku/brew/heroku

3. Heroku でアプリケーションを作成する

Kotlin + Spring Boot で作ったタスクを定期実行するアプリケーションを Heroku のアプリケーションとして作成します。

heroku create springboot-kotlin-batch

springboot-kotlin-batch は自分のアプリケーション名です。

この時、ブラウザが開きログインを求められると思います。
アカウントがあればログインし、無ければそのまま作成してください。
ブラウザでのログインに成功すると、アプリケーションの作成も自動で完了します。

$ heroku create springboot-kotlin-batch
Creating ⬢ springboot-kotlin-batch... !
 ▸    Invalid credentials provided.
heroku: Press any key to open up the browser to login or q to exit:
 ›   Warning: If browser does not open, visit https://cli-auth.heroku.com/auth/browser/c045769b-ea2c-43cd-94ff-eaca3d4ffab3
Logging in... done
Logged in as メールアドレス
Creating ⬢ springboot-kotlin-batch... done
https://springboot-kotlin-batch.herokuapp.com/ | https://git.heroku.com/springboot-kotlin-batch.git

4. Heroku にデプロイする

それでは、先程 Git 管理下においたソースを Heroku にデプロイしてみましょう! Heroku に push するだけでデプロイが実行されます。

git push heroku master

デプロイが完了するとこんな感じになると思います。

$ git push heroku master
Counting objects: 28, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (17/17), done.
Writing objects: 100% (28/28), 55.33 KiB | 9.22 MiB/s, done.
Total 28 (delta 0), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Gradle app detected
remote: -----> Spring Boot detected
remote: -----> Installing JDK 1.8... done
remote: -----> Building Gradle app...
remote: -----> executing ./gradlew build -x test
remote:        Downloading https://services.gradle.org/distributions/gradle-4.10.2-bin.zip
remote:        ..........................................................................
remote:
remote:        Welcome to Gradle 4.10.2!
remote:
remote:        Here are the highlights of this release:
remote:         - Incremental Java compilation by default
remote:         - Periodic Gradle caches cleanup
remote:         - Gradle Kotlin DSL 1.0-RC6
remote:         - Nested included builds
remote:         - SNAPSHOT plugin versions in the `plugins {}` block
remote:
remote:        For more details see https://docs.gradle.org/4.10.2/release-notes.html
remote:
remote:        > Task :compileKotlin
remote:        > Task :compileJava NO-SOURCE
remote:        > Task :processResources
remote:        > Task :classes
remote:        > Task :bootJar
remote:        > Task :inspectClassesForKotlinIC
remote:        > Task :jar SKIPPED
remote:        > Task :assemble
remote:        > Task :check
remote:        > Task :build
remote:
remote:        BUILD SUCCESSFUL in 33s
remote:        4 actionable tasks: 4 executed
remote: -----> Discovering process types
remote:        Procfile declares types     -> (none)
remote:        Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote:        Done: 62.4M
remote: -----> Launching...
remote:        Released v3
remote:        https://springboot-kotlin-batch.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/springboot-kotlin-batch.git
 * [new branch]      master -> master

5. 動作確認

デプロイが完了したので、既にアプリケーションの実行が開始されているはずです。
Heroku のログを見て確認してみましょう。

heroku logs -t

「はろー、わーるど!」と出ていれば成功です🎉

$ heroku logs -t
2018-12-03T07:39:14.182175+00:00 app[api]: Initial release by user 自分のメールアドレス
2018-12-03T07:39:14.182175+00:00 app[api]: Release v1 created by user 自分のメールアドレス
2018-12-03T07:39:14.401472+00:00 app[api]: Release v2 created by user 自分のメールアドレス
2018-12-03T07:39:14.401472+00:00 app[api]: Enable Logplex by user 自分のメールアドレス
2018-12-03T07:43:06.000000+00:00 app[api]: Build started by user 自分のメールアドレス
2018-12-03T07:43:50.728881+00:00 app[api]: Deploy 73bb6fa3 by user 自分のメールアドレス
2018-12-03T07:43:50.728881+00:00 app[api]: Release v3 created by user 自分のメールアドレス
2018-12-03T07:43:50.745994+00:00 app[api]: Scaled to web@1:Free by user 自分のメールアドレス
2018-12-03T07:43:55.224660+00:00 heroku[web.1]: Starting process with command `java -Dserver.port=34349 $JAVA_OPTS -jar build/libs/*.jar`
2018-12-03T07:43:57.543451+00:00 app[web.1]: Create a Procfile to customize the command used to run this process: https://devcenter.heroku.com/articles/procfile
2018-12-03T07:43:57.588489+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2018-12-03T07:43:57.595830+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8
2018-12-03T07:44:01.278185+00:00 app[web.1]:
2018-12-03T07:44:01.278249+00:00 app[web.1]: .   ____          _            __ _ _
2018-12-03T07:44:01.278283+00:00 app[web.1]: /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
2018-12-03T07:44:01.278339+00:00 app[web.1]: ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
2018-12-03T07:44:01.278404+00:00 app[web.1]: \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
2018-12-03T07:44:01.278454+00:00 app[web.1]: '  |____| .__|_| |_|_| |_\__, | / / / /
2018-12-03T07:44:01.278520+00:00 app[web.1]: =========|_|==============|___/=/_/_/_/
2018-12-03T07:44:01.294856+00:00 app[web.1]: :: Spring Boot ::        (v2.1.1.RELEASE)
2018-12-03T07:44:01.294881+00:00 app[web.1]:
2018-12-03T07:44:01.648240+00:00 app[web.1]: 2018-12-03 07:44:01.634  INFO 4 --- [           main] c.m.s.SpringbootKotlinBatchApplicationKt : Starting SpringbootKotlinBatchApplicationKt on d67c7ffc-1c9b-4090-b075-17cee0909c26 with PID 4 (/app/build/libs/springboot-kotlin-batch-0.0.1-SNAPSHOT.jar started by u57903 in /app)
2018-12-03T07:44:01.649378+00:00 app[web.1]: 2018-12-03 07:44:01.649  INFO 4 --- [           main] c.m.s.SpringbootKotlinBatchApplicationKt : No active profile set, falling back to default profiles: default
2018-12-03T07:44:02.000000+00:00 app[api]: Build succeeded
2018-12-03T07:44:06.409003+00:00 app[web.1]: 2018-12-03 07:44:06.408  INFO 4 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'taskScheduler'
2018-12-03T07:44:07.031812+00:00 app[web.1]: 2018-12-03 07:44:07.031  INFO 4 --- [           main] c.m.s.SpringbootKotlinBatchApplicationKt : Started SpringbootKotlinBatchApplicationKt in 7.15 seconds (JVM running for 9.433)
2018-12-03T07:44:12.019978+00:00 app[web.1]: はろー、わーるど!
2018-12-03T07:44:22.020616+00:00 app[web.1]: はろー、わーるど!
2018-12-03T07:44:32.021084+00:00 app[web.1]: はろー、わーるど!

以上ですべての作業が完了です。
おつかれさまでした!

📌 さいごに

やってみると分かりますが、本番公開まで手軽に一瞬でできてしまうのが素晴らしいですね。
Heroku は無料プランなのでお金もかかりません。

単純にバッチ処理の実行として使うこともできますが、その他に Twitter のボットや LINE のボットなどでも利用できそうです。
※ Twitter はアプリケーションを作成するのに審査が厳しくなってしまいましたが…。

近々、 LINE のボットは作ってみようと思うので、またその時に行ったことを記事にしようと思います。

さいごに、今回作成したアプリケーションを GitHub で公開します。

github.com