冷蔵庫の残り物でチャーハンを作る感覚をNode-REDから学ぶ

こんにちは。Leverages新卒エンジニアの[wataru-script](https://github.com/wataru-script)と申します。
Rubyをこよなく愛するエンジニアですが、最近はPythonとjsと戯れる日々を送っています。
生まれも育ちも福岡県の田舎なので、そろそろ方言を我慢できなくなりつつあります。
標準語えすかー。

この記事は[Leverages Advent Calendar 2017](https://qiita.com/advent-calendar/2017/engineer)の15日目の記事です。
業務中に作成したアプリケーションが個人的にツボにハマったので、記事にしてみました。
なんか雑記感はありますが、お読みいただけますと幸いです。

# きっかけ
バッチを回す際のプロセスおよびエラーをログに吐き出しているのですが、
バッチが終了しているかどうか目視するのは非常に面倒だったので、自動化してみました。

設計は大きく3つの機能に分けました。

- ログファイルを定期的に監視する機能(ShellScript)
- DBに監視結果を保存する機能(Ruby)
- バッチの結果をRocketChatに通知する機能(ShellScript)

こんな感じでざっくり開発を開始しました。


# ログファイルを定期的に監視する機能
終了のきっかけさえ分かれば、ShellScriptだけで実装できます。
「終了」の文字がログに含まれていれば成功、含まれていなければ失敗と判断します。

```shell:check.sh
#!/bin/bash

while :
do
    a=`find ./ -name $1.log -exec grep -H "終了" {} \;`
    b=`cat $1.log | wc -l`

    if [ $b !=0 ]; then
        if [[ $a != "" ]]; then
            check=($1 1)
            echo ${check[@]}
            exit 0
        else
            check=($1 -1)
            echo ${check[@]}
            exit 0        
        fi
    fi
done
```
こんな感じですね。

```bash check.sh {ファイル名から拡張子を除いたもの}```
で実施します。

第一引数で指定したファイルを監視して、
「終了」が含まれていれば、成功とみなして

```[{ファイル名から拡張子を除いたもの},1] ```
といった配列を返します。

「終了」が含まれていなければ、失敗とみなして
```[{ファイル名から拡張子を除いたもの},-1] ```
といった配列を返します。

# DBに監視結果を保存する機能
Ruby + SQLite3 + ActiveRecordを使って実装しました。

```ruby:check.rb
require 'active_record'

ActiveRecord::Base.establish_connection(
    "adapter" => "sqlite3",
    "database" => "./logcheckdb.sqlite3"
)

class Check < ActiveRecord::Base
end

 Check.where(:file => ARGV[0].to_s).update_all(:flag => ARGV[1].to_i)

if !Check.where(:flag => -1).to_a.empty? == true then
	Check.where(:file => ARGV[0].to_s).update_all(:flag => 0)
	p 0
elsif Check.where(:flag => 1).to_a.size ==  Check.all.to_a.size then
	p 1
end
```

ざっくりこんな感じ。

```ruby check.rb {fileカラムの値} {flagカラムの値}```で実施します。
ちなみに対象となるCheckテーブルには以下のようなデータが格納されています。

| file | flag |
|:-:|:-:|
| test1  | 0  |
| test2 | 1  |
| test3  | -1  |

fileカラムには監視対象となるログファイル名から拡張子をのぞいた文字列、
flagカラムにはログファイルの状況を示す整数値を挿入します。
それぞれの整数値はバッチの実行状況を表現しており

| 整数値 | 状態 |
|:-:|:-:|
|  0 | 実行中  |
|  1 |  成功 |
| -1  |  失敗 |
 
を意味します。

テーブルに一つでもflagカラムに-1が格納されていれば0を出力、
すべてのレコードに1が格納されていれば1を出力します。
flagカラムはデフォルトで0を格納しておきます。
よくわからない出力方法をしていますが、気にしない気にしない(一休さん風に)

# バッチの結果をRocketChatに通知する機能(ShellScript)
RocketChatのWebhook URLを使用して、curlでリクエストを飛ばします。

```shell:notification.sh
#!/bin/bash

ROCKETCHAT_API="https://hogehoge"


if [[ $1 == 1 ]]; then
    curl -X POST --data-urlencode 'payload={"username": "check_bot", "text": "成功やん!!!", "icon_emoji": ":grin:"}' $ROCKETCHAT_API
    exit 0
fi
if [[ $1 == 0 ]]; then
    curl -X POST --data-urlencode 'payload={"username": "check_bot", "text": "失敗してるよ!!!", "icon_emoji": ":frowning:"}' $ROCKETCHAT_API
    exit 0
fi
```

簡単簡単。

第一引数が1の時は成功メッセージ、0のときは失敗メッセージを指定のチャンネルにつぶやきます。

# 結合
それぞれのアプリケーションが比較的簡単にできました。
普段であれば、Rubyに統一したアプリケーションを作るのですが、
監視フローで使用する引数が多いため、更なる設計が必要です。

残念ながらそんな時間は私にはありませんでした。(遠い目)
機能は完成しているから、あとはフローを管理すればいいだけなのに…

そこでNode-REDの出番です！

# Node-RED
機能となるノードをGUIで配置および接続し、アプリケーションを作成することが出来ます。
これを利用して、先程作ったアプリケーションをノード化し、結合します。

実際に結合した様子がこちらです。

![node_check.png](https://qiita-image-store.s3.amazonaws.com/0/132626/6139d956-ec5d-8b50-629f-1f33ac0f089c.png)

ぱっと見ただけだとなにが起きているのかわからないので、書き込みを加えるとこうなります。

![書き込み.png](https://qiita-image-store.s3.amazonaws.com/0/132626/45748e0b-966f-1b04-90fe-a2a4e1b8c570.png)

あとは入力のタイミングを設定してあげればcronで動かすデーモンプロセスとして使用できます。
なんとも簡単！

# まとめ
ありあわせの機能でささっとアプリケーションが作れちゃいました。
これなら言語を統一することなく、処理はプログラミングで、フローはNode-REDで開発可能です。
フローが一緒であれば他機能のアプリケーションも作れちゃいます。
是非お試しを。

# ところで
開発中に思っていたのですが、

普段であれば、Rubyに統一したアプリケーションを作る = 開発が億劫であることの言い訳
ありあわせの機能 = 冷蔵庫の残り物
機能となるノードをGUIで配置および接続し、アプリケーションを作成 = ありあわせの食材をまとめる
フローが一緒であれば他機能のアプリケーションも作れる = 材料は違えど作り方は同じ

こ、これは…！

以上、冷蔵庫の残り物でできる簡単チャーハンの作り方についてでした。(えっ)