rubyのスクリプトの終了時に何か処理をしたい。
- エラーで落ちた時に、途中経過を保存しておきたい。
- 無事終了したら、メールを送る
- スレッドが死んだらどうするか
本来なら、ちゃんと例外処理や、ループ抜ける処理を書くべきなんです。
本来なら、ちゃんと例外処理や、ループ抜ける処理を書くべきなんです。
でも、無精したい時もあるし、すべての例外を受け止めるのもなんだかな。
終了処理を書く
とりあえず基本形
#!/usr/bin/env ruby begin loop{ sleep 10*10*10} rescue SignalException => e puts e.message puts e.backtrace end
実行して止める
takuya@air:~/Desktop$ ruby sinaltest.rb ^C sinaltest.rb:4:in `sleep' sinaltest.rb:4 sinaltest.rb:4:in `loop' sinaltest.rb:4
スレッドの終了処理
子スレッドも終了時になんかかせたい。
#!/usr/bin/env ruby class Bar < Thread def Bar.callback proc { puts "bar" } end def initialize ObjectSpace.define_finalizer(self,Bar.callback) super end end #メイン処理 begin t =[] t << Bar.new{ Thread.pass; loop{puts 1; sleep 1;Thread.pass} } t << Thread.new{ Thread.pass; loop{puts 2; sleep 1;Thread.pass} } loop{ puts 0; sleep 1} rescue SignalException => e puts e.message puts e.backtrace t.each{|a| a.kill} end
実行
takuya@air:~/Desktop$ ruby sinaltest.rb 1 0 2 0 1 2 ^C#⇐止める sinaltest.rb:23:in `sleep’ #⇐rescueが実行される sinaltest.rb:23 sinaltest.rb:23:in `loop' sinaltest.rb:23 bar # thread.killにより、object.finalizerが実行される。
スレッドの終了処理:パターン2(一番シンプル?)
スレッド終了処理はもっとシンプルにできそう
#!/usr/bin/env ruby class Thread def Thread.callback proc { puts "bar" } end end #メイン begin t =[] t << Thread.new{ Thread.pass; loop{puts 1; sleep 1;Thread.pass} } ObjectSpace.define_finalizer(t[0],Thread.callback) loop{ puts 0; sleep 1} rescue SignalException => e puts e.message puts e.backtrace t.each{|a| a.kill} end
クラスメソッドで共有されてProc使うのがなんか。。。
パターン3(特異クラスを使う)
#!/usr/bin/env ruby class Thread def Thread.callback proc { puts "bar" } end end #main begin t =[] t << Thread.new{ Thread.pass; loop{puts 1; sleep 1;Thread.pass} } class << t[0] ObjectSpace.define_finalizer(self,Thread.callback) end loop{ puts 0; sleep 1} rescue SignalException => e puts e.message puts e.backtrace t.each{|a| a.kill} end
動かない例
#!/usr/bin/env ruby class Thread def Thread.callback proc { puts "bar" } end ObjectSpace.define_finalizer(self,Thread.callback) end begin t =[] t << Thread.new{ Thread.pass; loop{puts 1; sleep 1;Thread.pass} } loop{ puts 0; sleep 1} rescue SignalException => e puts e.message puts e.backtrace t.each{|a| a.kill} end
selfが参照できないので、動かない。
スレッドが落ちたときに処理したいと思ったけどなかなか面倒なのでした
参考資料
終了処理
http://www.ruby-lang.org/ja/old-man/html/_BDAACEBBBDE8CDFD.html
Interrupt
http://www.ruby-lang.org/ja/old-man/html/SignalException.html
Exception
http://www.ruby-lang.org/ja/old-man/html/Exception.html
trap
http://www.ruby-lang.org/ja/old-man/html/_C1C8A4DFB9FEA4DFB4D8BFF4.html#trap
Signal::trap