2015-01-04 4 views
5

私のスクリプトは、redisデータベースの要素からいくつかの作業をしている要素を取得します。スクリプトが^ Cまたは他のシグナルで終了した場合、その要素はデータベースに返されることを確認する必要があります。 私はそれをRubyのトラップコンテキストでRedis呼び出しを使用するにはどうすればよいですか?

require "redis" 

class Test 
    attr_reader :quit 

    def initialize 
    @redis = Redis.new 
    end 

    def trap_signal 
    trap("INT") { 
     puts "get ready to exit" 
     @redis.rpush "TestQueue", @elem # I need to be sure that @emelent always puts back in the database 
     @quit = true} 
    end 

    def run! 
    trap_signal 
    @elem = "test string" 
    @redis.rpush "TestQueue", @elem 
    while !quit 
     @redis.blpop "TestQueue", @elem 
     # Do some work whith @element 
     sleep 1 
     # And put it back in the database 
     @redis.rpush "TestQueue", @elem 
    end 
    end 

end 

Test.new.run! 

を行うが、あなたのコードはすでにちょうどシグナルハンドラから@redis.rpushを削除し、正常に動作

^Cget ready to exit 
/usr/lib/ruby/2.1.0/monitor.rb:185:in `lock': can't be called from trap context (ThreadError) 
    from /usr/lib/ruby/2.1.0/monitor.rb:185:in `mon_enter' 
    from /usr/lib/ruby/2.1.0/monitor.rb:209:in `mon_synchronize' 
    from /home/kusayu/.gem/ruby/2.1.0/gems/redis-3.2.0/lib/redis.rb:37:in `synchronize' 
    from /home/kusayu/.gem/ruby/2.1.0/gems/redis-3.2.0/lib/redis.rb:991:in `rpush' 
    from test.rb:13:in `block in trap_signal' 
    from test.rb:24:in `call' 
    from test.rb:24:in `sleep' 
    from test.rb:24:in `run!' 
    from test.rb:32:in `<main>' 
+0

あなたはトランザクションロックを参照していますか?はい、あなたはhttp://redis.io/topics/transactionsを読むべきです – kiddorails

+0

@kiddorails私はトランザクションを使用しません、私はちょうど中断時にredis構造に私のアプリの現在の状態を保存する必要があります。このエラーは落胆しているようですが、なぜそれが起こるかわかりません。 – kusayu

答えて

3

このエラーを取得しようとしています。

シグナルハンドラでは「重い」操作を実行しないでください(とにかく、例外が発生するため)。 @quit = trueのような変数を使用してメインループに信号を送り、終了するタイミングを通知してから、メインループが適切なクリーンアップを処理するようにする方がはるかに優れています。あなたは自分のINTシグナルハンドラから@redis.rpushを削除する場合

だから、あなたはメインループのみ@quittrueで一度終了しますので、要素が戻ってデータベースに返されることを保証します。

+1

私はあなたの答えをupvoteするのに十分な評判はありませんが、私はあなたに感謝したいと思います。あなたは文字通りより多くの眠れない夜から私を救った。 – kusayu

関連する問題