Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

ruby

redis

My script gets elements from redis database end doing some work with it. I need to be sure that if script finishes with ^C or other Signal, the element will be returned back in 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>'
like image 763
kusayu Avatar asked Jan 04 '15 12:01

kusayu


1 Answers

Your code already works properly, just remove the @redis.rpush from the signal handler.

You shouldn't run "heavy" operations in the signal handler (and you get an exception because of it anyway). It's much better to use a variable like @quit = true to signal the main loop that it's time to finish, and then let the main loop handle the proper cleanup.

So if you just remove the @redis.rpush from your INT signal handler, then you will ensure that the element is returned back into the database because the main loop will only finish once @quit is true.

like image 174
Casper Avatar answered Oct 19 '22 12:10

Casper