连接池返回Redis的实例,而不是ConnectionPool

时间:2013-02-16 21:32:47

标签: ruby ruby-on-rails-3 redis

我正在努力让我的Rails应用程序使用Resque来管理员工。但是,我想继续使用ConnectionPool gem。

我在初始化程序中有这个:

puts ENV["REDISTOGO_URL"]

uri = (not ENV["REDISTOGO_URL"].nil?) ? URI.parse(ENV["REDISTOGO_URL"]) : nil

# at this point, debugger confirms $redis is nil
$redis = ConnectionPool::Wrapper.new(:size => 5, :timeout => 3) { 
  if uri.nil?
    Redis.connect
  else
    Redis.connect(:host => uri.host, :port => uri.port, :password => uri.password) 
  end
}

$redis # just put this in here for the debugger
       # At this point, $redis is #<Redis:0x007fb1b0036bf0>
       # when it should be an instance of ConnectionPool::Wrapper

有没有人知道为什么$redis不会作为实例ConnectionPool::Wrapper返回?

我搜索了所有宝石源代码,无处设置$redis的值。在ConnectionPool的源代码中,我没有找到任何可以返回Redis实例而不是其自身的内容。

仅当我从DelayedJob切换到Resque时才会发生这种情况。所以,这似乎是问题所在。但是,我很茫然。

我正在使用Unicorn。这是config中的该文件。

worker_processes 2
timeout 30
preload_app true

before_fork do |server, worker|
  # Replace with MongoDB or whatever
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
    Rails.logger.info('Disconnected from ActiveRecord')
  end

  # If you are using Redis but not Resque, change this
  if defined?(Resque)
    Resque.redis.quit
    Rails.logger.info('Disconnected from Redis')
  end

  sleep 1
end

after_fork do |server, worker|
  # Replace with MongoDB or whatever
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
    Rails.logger.info('Connected to ActiveRecord')
  end

  # If you are using Redis but not Resque, change this
  if defined?(Resque)
    # Yes, commented the Resque out for debugging, still get the same problem.
    #Resque.redis = ENV['REDISTOGO_URL']
    Rails.logger.info('Connected to Redis')
  end
end

最后,Procfile:

web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
worker: env TERM_CHILD=1 QUEUE=* bundle exec rake resque:work

我在开发环境中使用foreman

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

来自文档:

  

您可以使用ConnectionPool :: Wrapper来包装单个全局连接。

我看起来ConnectionPool::Wrapper旨在将单个连接包装到Redis,以方便将大型应用程序从使用Redis直接迁移到使用ConnectionPool

如果您致电$redis.with,则会获得#with定义的ConnectionPool

要获得实际的连接池,只需更改

即可
ConnectionPool::Wrapper.new(:size => 5, :timeout => 3) { #redis logic }

ConnectionPool.new(:size => 5, :timeout => 3) { #redis logic }

答案 1 :(得分:1)

内部ConnectionPool :: Wrapper创建一个普通的ConnectionPool对象,并且只要在包装器上调用任何方法,就使用method_missing自动从该池中签出/签入。

method_missing的这种使用包括对inspectclass的调用,或通常用于尝试查看对象或找出其类型的任意数量的方法。

require 'connection_pool'

class MyClass
  def foo
    'bar'
  end
end

obj = MyClass.new
obj.respond_to?(:foo) # true
obj.respond_to?(:with) # false  

wrapper = ConnectionPool::Wrapper.new { MyClass.new }
wrapper.respond_to?(:foo) # true
wrapper.respond_to?(:with) # also true! 'with' is a method on ConnectionPool::Wrapper

你有一个ConnectionPool :: Wrapper的实例,它有点难以辨别。