rubyどこまでensureされるのか
ゾンビプロセスの対処に非常に困ってるんだけど、一つの原因にsidekiqから呼び出す外部コマンドがゾンビになってるような挙動があるので、確実にsidekiqのワーカの子プロセスを殺す仕組みがほしいのだけど、そのときにensureって使って良いのかとふと思った。
begin pid1 = POSIX::Spawn.spawn("convert hoge -background white -alpha Remove fuga.jpeg")・・・・・(※1) Process.waitpid(pid1) ensure Process.kill(pid1)・・・・・・(※2) end
この※1の処理の時間が長かった時、このスクリプト自体のプロセス(Railsだったりsidekiqだったり)が死んだら、※2は呼ばれると思いますか?
僕もちゃんとわかってなかったのでちょっと実験してみました。
begin sleep(100) ensure puts 'ensure!!' end
このコードをensure.rb
という名前にして、ruby ensure.rb
として呼び出します。
あとはps ax | grep ensure.rb
としてプロセスのpidを得ます。
$ ps ax | grep ensure.rb 54817 s007 S+ 0:00.04 ruby ensure.rb
実験というのは、このプロセスにシグナルを送ってどういう挙動をするのか見るというものです。
- Ctrl-C
まずruby ensure.rb
を動かすとプロンプトが100秒固まるので、これをCtrl-C
で止めてみます。
$ ruby ensure.rb ^Censureed!! ensure.rb:2:in `sleep': Interrupt from ensure.rb:2:in `<main>'
ensureされています。
- kill -9
次に9オプション(強制終了)でプロセスを止めてみます。
$ ruby ensure.rb [1] 54950 killed ruby ensure.rb
ensureが表示されません。
というわけで、結論から言えばensureが実行される時とされない時があるといえます。
状況の違い
今度はどういうときに実行され、どういうときに実行されないかですが非常にわかりやすいサイトがありました。
上のサンプルの実行だとSIGKILL以外の
- SIGHUP
- SIGINT
- SIGTERM
- SIGTSTP
シグナルではensureが呼ばれた。このページでもSIGKILLでは正常な終了処理が保証されないとあるので、たぶん今回のようにゾンビを殺すような処理は書いてもOKだろうと思う。