読者です 読者をやめる 読者になる 読者になる

プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

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

実験というのは、このプロセスにシグナルを送ってどういう挙動をするのか見るというものです。

  1. 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されています。

  1. kill -9

次に9オプション(強制終了)でプロセスを止めてみます。

$ ruby ensure.rb
[1]    54950 killed     ruby ensure.rb

ensureが表示されません

というわけで、結論から言えばensureが実行される時とされない時があるといえます。

状況の違い

今度はどういうときに実行され、どういうときに実行されないかですが非常にわかりやすいサイトがありました。

equj65.net

上のサンプルの実行だとSIGKILL以外の

  • SIGHUP
  • SIGINT
  • SIGTERM
  • SIGTSTP

シグナルではensureが呼ばれた。このページでもSIGKILLでは正常な終了処理が保証されないとあるので、たぶん今回のようにゾンビを殺すような処理は書いてもOKだろうと思う。