ClockworkとDockerでRubyスクリプトの定期実行

## これは何？
* `Ruby` を定期実行したい！
* `Ruby` には定期実行が簡単に実行できる `Clockwork` がある！
* `Docker` を使ってもっともっと簡単に実行できるようにしたい！(`cron` を導入したりとか面倒なこともしたくない)

ということでしてみましたのでそのご紹介と知見共有です

## Clockworkとは
* [Clockwork](https://github.com/adamwiggins/clockwork)

`Ruby` の定期実行用 `Gem`。
定期実行といえば `cron` が有名であり、さらに `Ruby` で定期実行となれば `whenever` が有名かと思います。
`Clockwork` を使えば上記のツールを使うように簡単に定期実行を行う事ができます。

細かな話は以下のような記事や上記の公式ドキュメントをご確認ください

* [clockworkでRubyスクリプトを定期実行しよう](https://qiita.com/giiko_/items/7e7c91a50f66bb351c89)
* [clockwork について](https://www.ownway.info/Ruby/clockwork/about)

## 試してみる
* [clockwor_docker](https://gitlab.com/sample-by-toririn/clockwork_docker)

上記のリポジトリに確認できるコードを置いています。自由に使ってください。
※もちろん `Docker` の環境が必要です

### 1.ソースコードのクローン
上記ソースコード一式を `clone` してきてください

```shell
git clone https://gitlab.com/sample-by-toririn/clockwork_docker.git
```

### 2.イメージの作成
以下のコマンドで `Docker Image` を作成してください


```shell
docker build -t clock_test .
```

### 3.コンテナの作成
以下のコマンドでコンテナを作成してください

```shell
docker run --name clock_test -v `pwd`:/usr/src/app -d clock_test
```

### 4.ログの確認
以下のコマンドでログを確認してください

```shell
docker logs -f clock_test
```

以下のようなログが次々と出て入れば無事定期実行が動いています

```
I, [2019-08-10T00:52:35.005344 #1]  INFO -- : Triggering 'test'
2019年08月10日の00時52分35秒だよ！
I, [2019-08-10T00:52:35.005344 #1]  INFO -- : Triggering 'test'
2019年08月10日の00時52分38秒だよ！
```

※時間は実行した時間が表示されるかと思います

### 5.ちょっとした修正

コンテナ作成時に `-v` オプションをつけていたので直接コードを修正してください。
修正ができればコンテナを再起動することで反映がされます

```shell
docker restart clock_test
```

## 仕組み

仕組みというほどのことはありませんが、単純に `Ruby` の公式イメージに `Clockwork` をインストールし実行をしているだけです。

### Dockerfile

以下が `Dockerfile` です

```Dockerfile
FROM ruby:2.6.3-slim-stretch
ENV LANG C.UTF-8
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN bundle install

CMD ["bundle", "exec", "clockwork", "config/clock.rb"]
```

5行目でイメージを作成するときにソースコード一式をイメージに入れています。
6行目で `clockwork` のインストールを行なっています
最後にコマンドで `clockwork` を実行しています

### config/clock.rb

以下が `clockwork` の設定ファイルです(一部省略)

```ruby
# 定期実行で利用するクラスの読み込み
require_relative '../lib/clock_test'

# Clockworkを利用するためにモジュールを読み込み
include Clockwork
# 定期実行で利用するクラスの読み込み
include ClockTest

# Clockworkの設定値
configure do |config|
  # 日本時間のタイムゾーンを設定
  config[:tz] = "Asia/Tokyo"
end

# ...省略

# 3秒に1回実行
every(3.seconds, "test") do
  Foo.new.run
end
```

説明は書いている通りです。
`clockwork` の設定側でタイムゾーンに日本時間を設定しています。こちらがなければ `UTC` で実行されることになります。
この設定もなくしたければ `Docker Image` のシステム時間を日本時間に変更することでも対応できます

ログで確認できたのは3秒に1回実行される設定をしていたところです

### Foo.new.run

以下が `Foo` クラスの中身です

```ruby
require_relative "logger"
module ClockTest
  class Foo
    def run
      current_time = Time.new.strftime("%Y年%m月%d日の%H時%M分%S秒だよ！")
      Logger.info(current_time)
    end
  end
end
```

ただ現在時刻をとってきてログに出しているだけです。

しかし `Docker` で `Ruby` の `Time` クラスを使うのには注意が必要です

### `Ruby` が利用するタイムゾーンを設定する

以下が設定を行なっている `initialize.rb` の中身です

```ruby
require "time"
# 時間を日本時間にする
ENV["TZ"] = "Asia/Tokyo"
```

`Ruby` は `TZ` という環境変数にタイムゾーンの地域を設定していれば、そのタイムゾーンを使ってくれます。
もし上記の設定がなければシステムのタイムゾーンが使われます。

だいたいのピュアな `Docker Image` は `UTC` になっているので、上記の設定を追加して日本時間のタイムゾーンを設定しています。

これで `Time.new` で取得される時刻オブジェクトは日本時間のものになりました。

#### 補足
ここで設定しなくても `Dockerfile` で `ENV` の設定を記載することでも日本時間に変更することは可能です！


参考: [Rubyのタイムゾーン](https://qiita.com/jnchito/items/cae89ee43c30f5d6fa2c#part-1-%E7%B4%A0%E3%81%AEruby%E3%81%AE%E5%A0%B4%E5%90%88)


## まとめ
* `Docker` + `Ruby` で定期実行処理はとても簡単にできる