rubyスクリプト内でタイムアウトした時にプロセスをKILLする
お仕事でいろんな監視スクリプトを組んでミドルウェアやデーモンなどの監視をしています。
大体がrubyのスクリプトで作っているのですが、そこで一部はまったことを記録しておきます。
監視の本体はHobbitというツールを使っています。
監視のスクリプトは各サーバで実行され、実行結果をHobbitのマスターに送信するという感じになっています。
今回は定期的にapacheのmod_statusのデータを取得し、httpdのプロセスの状態を監視するスクリプトで起きた現象です。
スクリプト自体はたいしたことをしていなくて
- mod_statusのデータを取得
- データを加工して欲しい情報に整形
- システムコマンドを叩いて追加データの取得
- hobbitにデータ送信
なんてことをしています。
問題はスクリプトがTimeOutした時に起こります。
timeout_time = 60 retry_count = 3 begin timeout(timeout_time) { # ここにアレやコレや(上記の1〜3)の処理 } rescue Timeout::Error => ex retry_count -= 1 puts Time.now.to_s + "=>" + retry_count.to_s if retry_count > 0 sleep 5 retry end end
スクリプトではTimeOutした時はエラーをキャッチしてリトライ処理をするようにしています。
大体はリトライで正常終了するのですが、リトライが掛かった時にシステムコマンドで起動したプロセスがスクリプト終了時も残ってしまい、psコマンドを打つと監視スクリプトから呼び出されたプロセスで一杯になってしまっていました。
※ プロセスが生成されるのは上述のシステムコマンドを叩いて追加データを取得するタイミング
対策として、スクリプトから起動したプロセスのpidを取得し、タイムアウト時にKILLするように修正しました。
pidを取るように修正
io = IO.popen('ps --no-headers -C php-cgi | wc -l') pid = io.pid cgi = io.read.chomp
プロセスをKILLするように修正
rescue Timeout::Error => ex retry_count -= 1 puts Time.now.to_s + " => " + retry_count.to_s # kill timeout process if pid > 0 puts "kill timeout process => " + pid.to_s Process.kill('KILL', pid) end if retry_count > 0 sleep 5 retry end end
これでタイムアウト時にプロセスをKILLすることができました。