それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Rubyの終了処理で何かする

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#&#8656;止める
sinaltest.rb:23:in `sleep’ #&#8656;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が参照できないので、動かない。

スレッドが落ちたときに処理したいと思ったけどなかなか面倒なのでした