[Heroku] Digdagを使ってスピンダウン時間を無くす（Ubuntu）


# 前置き

Slack用のbotを Kotlin / SpringMVC で作成して Heroku にデプロイしました。
しかし、スピンダウン時間は bot にとって致命的です。（ということが実際に使って痛感しました）

有料インスタンスを使えば済む話なのですが、今回はせっかくなので勉強もかねて、DigitalOceanで走らせているUbuntuインスタンスに、ジョブスケジューラである`Digdag`を入れてスピンダウンを回避したいと思います。

# スピンダウン

Heroku（に限らず多くのPaaS）には「スピンダウン」と言って、しばらくマシンリソースが利用されないとインスタンスがスリープ状態に入ります。

スリープ状態から復帰するのを「スピンアップ」というのですが、感覚的に30secくらいかかります。

botに書き込んだら、30secも反応が帰ってこないのは致命的と言えます。

# Herokuの無料インスタンスの場合

現時点では、Herokuのスピンダウンは30分間アクセスされない場合だそうです。（そのうち変わることもあるでしょう）
https://www.heroku.com/pricing
![Kobito.I2CIhn.png](https://qiita-image-store.s3.amazonaws.com/0/29653/3d504242-cc53-6acf-e031-c2ee51e25ef6.png "Kobito.I2CIhn.png")

なので、25分くらいの間隔でHTTPリクエストを送って、インスタンスをスピンダウンさせなければ良さそうです。

P.S.
Hobbyプランが $7/month なので、素直にそちらを使うのが賢いと思います。
（が、繰り返しですがちょっとした勉強も兼ねて）

# Digdagのインストール

公式の Getting started を読みながらインストールします。
http://docs.digdag.io/getting_started.html

```bash
$ 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`の内容を再読込して反映させます。

```bash
$ source ~/.bashrc
```

# Digdag で Hello world

まずはそのまま公式のドキュメントに従って最初のサンプルを動かしてみます。

```bash
$ digdag init mydag
/home/xxxx/bin/digdag: line 138: exec: java: not found
```

と思いましたが、`Java`が無いとエラーになってしまいました。
そう、DigdagはJavaで書かれたワークフローエンジンでした。

# Javaのインストール

## SDKMAN!のインストール

今回は`SDKMAN!`を使ってインストールしたいと思います。
http://sdkman.io/


```bash
$ 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`をインストールします。

```bash
$ sudo apt-get update
$ sudo apt-get install zip unzip
```

両方ともインストールされているか確認。

```bash
$ which zip
$ which unzip
```

# SDKMAN!のインストール（つづき）

インストールの続きです。

```bash
$ 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!!!
```

公式どおりにコマンドを打ちます。

```bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
```

無事にインストール出来たようです。

```bash
$ 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のインストール

まずはインストール可能な一覧を調べてみます。

```bash
$ 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`の名前？らしいです。

```bash
$ 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.
```

無事にインストール出来たことが確認できます。

```bash
$ 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に戻ってこれました。

```bash
$ 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`を作成

以下のようなソースになりました。

```digdag:wakeup_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`で起動できるようです。

```bash
$ digdag scheduler &
[1] 12370
```

バックグラウンドで実行したいので`&`を末尾につけています。

# 終わり

というわけで、UbuntuにDigdagをインストールし、スケジューラを使ってHerokuのスピンダウンを抑えてみました。

まぁしかしこの労力を掛けるくらいなら、素直に有料インスタンスを使うのが良いとは思います。