前置き
Slack用のbotを Kotlin / SpringMVC で作成して Heroku にデプロイしました。
しかし、スピンダウン時間は bot にとって致命的です。(ということが実際に使って痛感しました)
有料インスタンスを使えば済む話なのですが、今回はせっかくなので勉強もかねて、DigitalOceanで走らせているUbuntuインスタンスに、ジョブスケジューラであるDigdag
を入れてスピンダウンを回避したいと思います。
スピンダウン
Heroku(に限らず多くのPaaS)には「スピンダウン」と言って、しばらくマシンリソースが利用されないとインスタンスがスリープ状態に入ります。
スリープ状態から復帰するのを「スピンアップ」というのですが、感覚的に30secくらいかかります。
botに書き込んだら、30secも反応が帰ってこないのは致命的と言えます。
Herokuの無料インスタンスの場合
現時点では、Herokuのスピンダウンは30分間アクセスされない場合だそうです。(そのうち変わることもあるでしょう)
https://www.heroku.com/pricing
なので、25分くらいの間隔でHTTPリクエストを送って、インスタンスをスピンダウンさせなければ良さそうです。
P.S.
Hobbyプランが $7/month なので、素直にそちらを使うのが賢いと思います。
(が、繰り返しですがちょっとした勉強も兼ねて)
Digdagのインストール
公式の Getting started を読みながらインストールします。
http://docs.digdag.io/getting_started.html
$ curl -o ~/bin/digdag --create-dirs -L "https://dl.digdag.io/digdag-latest"
$ chmod +x ~/bin/digdag
$ echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
.bashrc
の内容を再読込して反映させます。
$ source ~/.bashrc
Digdag で Hello world
まずはそのまま公式のドキュメントに従って最初のサンプルを動かしてみます。
$ digdag init mydag
/home/xxxx/bin/digdag: line 138: exec: java: not found
と思いましたが、Java
が無いとエラーになってしまいました。
そう、DigdagはJavaで書かれたワークフローエンジンでした。
Javaのインストール
SDKMAN!のインストール
今回はSDKMAN!
を使ってインストールしたいと思います。
http://sdkman.io/
$ curl -s "https://get.sdkman.io" | bash
Thanks for using...
SSSSSSSSSSSSSSS DDDDDDDDDDDDD KKKKKKKKK KKKKKKK
SS:::::::::::::::SD::::::::::::DDD K:::::::K K:::::K
S:::::SSSSSS::::::SD:::::::::::::::DD K:::::::K K:::::K
S:::::S SSSSSSSDDD:::::DDDDD:::::D K:::::::K K::::::K
S:::::S D:::::D D:::::DKK::::::K K:::::KKK
S:::::S D:::::D D:::::D K:::::K K:::::K
S::::SSSS D:::::D D:::::D K::::::K:::::K
SS::::::SSSSS D:::::D D:::::D K:::::::::::K
SSS::::::::SS D:::::D D:::::D K:::::::::::K
SSSSSS::::S D:::::D D:::::D K::::::K:::::K
S:::::S D:::::D D:::::D K:::::K K:::::K
S:::::S D:::::D D:::::DKK::::::K K:::::KKK
SSSSSSS S:::::SDDD:::::DDDDD:::::D K:::::::K K::::::K
S::::::SSSSSS:::::SD:::::::::::::::DD K:::::::K K:::::K
S:::::::::::::::SS D::::::::::::DDD K:::::::K K:::::K
SSSSSSSSSSSSSSS DDDDDDDDDDDDD KKKKKKKKK KKKKKKK
mmmmmmm mmmmmmm aaaaaaaaaaaaa nnnn nnnnnnnn
mm:::::::m m:::::::mm a::::::::::::a n:::nn::::::::nn
m::::::::::mm::::::::::m aaaaaaaaa:::::an::::::::::::::nn
m::::::::::::::::::::::m a::::ann:::::::::::::::n
m:::::mmm::::::mmm:::::m aaaaaaa:::::a n:::::nnnn:::::n
m::::m m::::m m::::m aa::::::::::::a n::::n n::::n
m::::m m::::m m::::m a::::aaaa::::::a n::::n n::::n
m::::m m::::m m::::ma::::a a:::::a n::::n n::::n
m::::m m::::m m::::ma::::a a:::::a n::::n n::::n
m::::m m::::m m::::ma:::::aaaa::::::a n::::n n::::n
m::::m m::::m m::::m a::::::::::aa:::a n::::n n::::n
mmmmmm mmmmmm mmmmmm aaaaaaaaaa aaaa nnnnnn nnnnnn
Now attempting installation...
Looking for a previous installation of SDKMAN...
Looking for unzip...
Not found.
======================================================================================================
Please install unzip on your system using your favourite package manager.
Restart after installing unzip.
======================================================================================================
でかでかとロゴが表示されましたが、どうやらunzip
コマンドが無いと怒られているようです。
Please install unzip on your system using your favourite package manager.
Restart after installing unzip.
zip/unzip をインストール
apt-get
を使って、zip
とunzip
をインストールします。
$ sudo apt-get update
$ sudo apt-get install zip unzip
両方ともインストールされているか確認。
$ which zip
$ which unzip
SDKMAN!のインストール(つづき)
インストールの続きです。
$ curl -s "https://get.sdkman.io" | bash
...
All done!
Please open a new terminal, or run the following in the existing one:
source "/home/yusuke/.sdkman/bin/sdkman-init.sh"
Then issue the following command:
sdk help
Enjoy!!!
公式どおりにコマンドを打ちます。
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
無事にインストール出来たようです。
$ sdk version
==== BROADCAST =================================================================
* 05/10/17: Groovy 2.5.0-beta-2 released on SDKMAN! #groovylang
* 02/10/17: Gradle 4.2.1 released on SDKMAN! #gradle
* 29/09/17: Kotlin 1.1.51 released on SDKMAN! #kotlin
================================================================================
SDKMAN 5.5.12+269
Javaのインストール
まずはインストール可能な一覧を調べてみます。
$ sdk list java
================================================================================
Available Java Versions
================================================================================
9.0.0-zulu
8u144-zulu
8u141-oracle
8u131-zulu
7u141-zulu
6u93-zulu
================================================================================
+ - local version
* - installed
> - currently in use
================================================================================
Digdag は Java9 では動かないらしい(というより動かなかった)ので、 8u144-zulu
をインストールしたいと思います。
ちなみにzulu
というのはOpenJDK
の名前?らしいです。
$ sdk install java 8u144-zulu
Downloading: java 8u144-zulu
In progress...
######################################################################## 100.0%
Repackaging Java 8u144-zulu...
Done repackaging...
Installing: java 8u144-zulu
Done installing!
Setting java 8u144-zulu as default.
無事にインストール出来たことが確認できます。
$ java -version
openjdk version "1.8.0_144"
OpenJDK Runtime Environment (Zulu 8.23.0.3-linux64) (build 1.8.0_144-b01)
OpenJDK 64-Bit Server VM (Zulu 8.23.0.3-linux64) (build 25.144-b01, mixed mode)
こんな感じでサクッとインストール出来て、SDKMAN!
はなかなか便利ですね。
(rbenv
のように複数バージョンをインストールできる、というのがメリットだとは理解しているのですが)
Digdag で Hello world
さて、ようやくDigdagに戻ってこれました。
$ digdag init mydag
2017-10-09 13:02:30 +0000: Digdag v0.9.17
Creating mydag/mydag.dig
Creating mydag/.gitignore
Done. Type `cd mydag` and then `digdag run mydag.dig` to run the workflow. Enjoy!
$ cd mydag
$ digdag run mydag.dig
...
何やらずらずらと表示されますが、どうやら成功したようです。
Heroku に定期的にアクセスする.dig
を作成
以下のようなソースになりました。
timezone: "Asia/Tokyo"
schedule:
cron>: "*/25 6-22 * * *"
+wakeup:
http>: https://xxxx.herokuapp.com/
最初はタイムゾーンの設定、その次がスケジュールの設定です。
スピンダウンを防ぐ時間帯を指定したいので、cron>:
で指定を行っています。
6時から22時の間、25分の間隔で処理、という感じですね。
+wakeup:
というのは自分でつけた名前です。
関数名みたいなものでしょうか。(正式名称を調べていないのですが)
最後にhttp>:
を利用して、Herokuのインスタンスにアクセスしています。
起動
同じディレクトリにいればdigdag scheduler
で起動できるようです。
$ digdag scheduler &
[1] 12370
バックグラウンドで実行したいので&
を末尾につけています。
終わり
というわけで、UbuntuにDigdagをインストールし、スケジューラを使ってHerokuのスピンダウンを抑えてみました。
まぁしかしこの労力を掛けるくらいなら、素直に有料インスタンスを使うのが良いとは思います。