2015-01-04 73 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! 

,但得到這個錯誤

^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 2015-01-04 12:54:17

+0

@kiddorails我不使用事務,我只需要將我的應用的當前狀態保存到中斷時的redis結構中。這個錯誤似乎令人沮喪,我無法弄清楚它爲什麼會發生。 – kusayu 2015-01-04 13:01:03

回答

3

您的代碼已經正常工作,只是從信號處理程序中刪除@redis.rpush

你不應該在信號處理程序中運行「重」操作(因爲它你會得到一個異常)。使用像@quit = true這樣的變量來告訴主循環是時候完成了,然後讓主循環處理正確的清理,這會更好。

所以,如果你只是從你的INT信號處理去除@redis.rpush,那麼你將確保元素被返回到數據庫中,因爲主循環將只完成一次@quittrue

+1

我沒有足夠的聲望來提高您的答案,但我想說聲謝謝。你從字面上挽救了我更多的不眠之夜。 – kusayu 2015-01-04 13:45:59