How could I use Redis calls in trap context in Ruby?

My script gets elements from the end of the redis database, doing some work with it. I have to be sure that if the script ends with ^ C or some other signal, the element is returned to the database. I'm trying to do it

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! 

but get this error

 ^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>' 
+5
source share
1 answer

Your code is already working correctly, just remove @redis.rpush from the signal handler.

You should not run β€œheavy” operations in the signal handler (and you will get an exception because of this anyway). It is much better to use a variable like @quit = true to signal to the main loop that it is time to complete, and then let the main loop handle the correct cleanup.

So, if you simply remove @redis.rpush from the INT signal handler, you will make sure that the element is returned back to the database, because the main loop will be completed only once @quit is true .

+3
source

Source: https://habr.com/ru/post/1210353/


All Articles