背景
- GCP Compute Engineの無料枠(f1 micro)を使い、Scala製のslack botアプリを走らせていた
- 貧弱メモリにより
sbt assembly
が通らず、sbt run
も数日でinsufficient memory for the Java Runtime Environment to continue
でout of memory
エラーを吐き出す
※sbt assemblyは通せた。が、数日で😇は相変わらず - 具体的にはサーバで使えるメモリが512MB(実質これ未満)で、JVMやsbtで使うヒープメモリ最大量などを128MBまで絞っても平気で堕ちる
- 毎回手作業でbotをザオリクするのがつらい…つらい…
概要
- cronで自動化する
- 厳密には生かし続けるのではなく、毎日ころしては生き返らせてコブシで新鮮なメモリを保つ
なんでメモリが漏れていくのだろうか…
手順
今回はsbt run
でやる場合を書く。
bot再起動スクリプトを用意する
date # 実行日時を出力
pkill -KILL java # `sbt run`で動いているはずのjavaプロセスを問答無用で黙らせる
export SCALA_BOT_TOKEN='...' # slack botのトークン
cd ~/Scala-IshiiBot/ # build.sbtがあるディレクトリ(たとえばScala-IshiiBot/)へ移動
setsid nohup sbt -mem 200 run & # sbt runをバックグラウンドで実行
exportでいちいち環境変数を設定し直している。
cron実行時のやつは使えなかった。。。なぜ。。。
SCALA_BOT_TOKENはScala製のslack botアプリで使うから入れた
setsid nohup
により、sshを切ってもコマンドは持続する。
-mem 200
を指定することで使用メモリ上限を抑えられる。
128MBだとプログラムのgoogle injectに押し潰されて😇となり、256MBだとGCP自体のメモリが耐えられず😇となる。
良い感じの落とし所は約200MBの模様。
スクリプトに実行権限をつける
これでcronから実行できる。
$ chmod +x ~/restart-bot.sh
cronを設定ファイルから登録
$ crontab setcron.txt
設定ファイルは予め作っておく。例えばホームディレクトリ名がv2okimochi
の場合はこうなる。
00 00 * * * ~/restart-bot.sh >> cronlog
これは、毎日00:00にホームディレクトリ
にあるrestart-bot.sh
を実行する&結果出力はcronlog
ファイルに追記していく、という意味。
out of memory
などのエラー情報が追記されていくので、何かエラーを吐いたらここを見れば良い。
エラー以外の情報もあって膨大なので、restart-bot.sh
側で実行日時を出力するようにした。これで日時から検索できる。
日本時間に合わせる
サーバがUTCなので、このままではUTC基準で動いてしまう。
日本時間JSTに合わせる。
$ sudo timedatectl set-timezone Asia/Tokyo
再起動が必要かもしれない。
再起動して再びssh接続すると、last login
の日時がJSTに変わる。
cronサービスが動いていることの確認
$ /etc/init.d/cron status
active(running)
みたいなのが返ってくれば多分動いてる。おk。
もし止まってたら動かす。
$ /etc/init.d/cron start
おまけ
毎回sbtするより最初にsbt assemblyでjarファイル作っておいてjarを毎回叩いたほうが実は速かったりしない?
と思うこともある。
assemblyでやる場合は、restart-bot.sh
はこうなる。
date
pkill -KILL java
export _JAVA_OPTIONS='-Xms128m -Xmx200m'
export SCALA_BOT_TOKEN='...'
nohup java -jar ~/Scala-IshiiBot/target/scala-2.12/slack-bot-scala-assembly-0.1.jar &