今回は負荷の高いRailsアプリのunicornが落ちてしまうことがあり、
手動で再起動しているようでは、ダウンタイムが発生してしまうのでなんとか自動的に再起動をかけられないかと考えさがしていたところ、
手軽にできる方法を発見し、暫定的に採用させていただきました。
もっと良い方法や違うアプローチがあるかもしれませんが、
今回は表題の内容を紹介させていただきます。
環境
- AWS EC2
- Ubuntu
- Rails
- Unicorn
restart-server
というunicorn
を再起動するコマンドを予め作成しておりましたので、
プロセスを監視してunicorn
がいなかったらそのスクリプトを実行するという形を取りました。
またデプロイ専用のユーザーで無いと、restart-server
は実行できないという環境です。
概要
linuxコマンドのwatch
を利用して、60秒ごとにunicorn
と含まれるプロセスが存在するかを確認、
プロセス数が0であれば、restart-server
を実行するという具合です。
ただssh
で接続してwatch
を実行してもwatch
を終了しなければ、sshを切断できませんので、
sshを繋ぎっぱなしにしなければなりません。
よってsshを切っても、watch
が動き続けるようにnohuo
を利用します。
それらを組み合わせてできたワンライナーが以下のものです。
nohup watch -n 60 "if [ 0 -eq `ps ax | grep unicorn | grep -v grep | wc -l` ] ; then restart-server ; fi" &
使用方法
{繰り返しの秒数}
のところに繰り返し監視する感覚を秒数で入力します。0.1以下は設定不可
{実行するコマンド}
のところに、unicornプロセスがなかったときに実行するコマンドを入力します。
{実行するコマンド}
の部分はあまり長いもの入れられませんので、別途スクリプトを用意するなどして簡単に呼び出せるようにすることが必要です。
nohup watch -n {繰り返しの秒数} "if [ 0 -eq `ps ax | grep unicorn | grep -v grep | wc -l` ] ; then {実行するコマンド} ; fi" &
以下、各部分を簡単に解説していきます。
nohup <command> &
先頭のnohup
と末尾の&
がnohup
コマンドです。
その間に半角スペースを挟んで、ssh切断後も実行しておきたいコマンドを入れます。
今回はwatch
コマンドです。
watch -n 60
この部分がwatch
コマンドとオプション指定です。
-n
が実行間隔を指定するオプションでその後に半角スペースにつづけて秒数を入力します。
if [ 0 -eq `ps ax | grep unicorn | grep -v grep | wc -l` ] ;
おなじみのif文です。[]
内が条件式です。
0 -eq
の部分がイコール0ならば真という条件式です。
続くps ax
が全てのプロセスを一覧表示するコマンド、|
パイプで繋いでgrep unicorn
でunicorn
を含むプロセスだけに絞り込みます。
ただこれだけだと、絞り込んだ結果の中にこのgrep
自体もプロセスも含まれてしまいますので、grep -v grep
でgrep
の実行プロセスを除外します。
最後のwc -l
でその絞り込んだ結果を数字にします。
そうすることで0 -eq
と数字で比較します。
unicorn
プロセスが居ないときは、プロセスリストにunicornと含まれるプロセスも0になりますので、
0と比較して真になれば、then
に続くコマンドが呼び出されるという形です。
注意点
当たり前のことかもですが、スペースに注意してください。
[]
や;
の前後のスペースが抜けるとうまくいきません。
あとクオートとバッククウォートにも注意が必要です。
if ~ fi
までがif文ですが、それをダブルクォーテーションでくくっています。
またps ~ -l
まではバッククウォートでくくっています。
まとめ
こんなワンライナーで済ませてしまっていいものかとも思いますが、
きちんとしたunicorn監視&再起動の方法があればご教授ください。
自分でも引き続き調べていこうと思います。
参考にした記事
以下の記事を参考にさせていただきました。
非常に助かりました。ありがとうございました。
grepでこういう時はどうする?
SSHからログアウトした後もプロセスを起動しておく方法
シェルスクリプト(bash)の「 [ ] 」と「 [[ ]] 」の違い
grepでこういう時はどうする?