2011-10-05 21 views
7

Estoy intentando escribir una función que intente conectarse a Redis usando la configuración TCP predeterminada, y si eso falla, intenta conectarse a Redis a través de un socket Unix. Mi intención es tener un único script de conexión que funcione en todos mis sistemas, algunos de los cuales usan TCP y otros que usan sockets.No se puede rescatar de la conexión negativa de Redis

Sin embargo, no puedo rescatar de la conexión TCP fallida. Aquí está mi script de prueba.

require "redis" 

def r 
    begin 
    $redis ||= Redis.new 
    rescue 
    $redis = Redis.new(:path => "/tmp/redis.sock") 
    end 
end 

puts "You have #{r.keys.count} redis keys" 

rescue El bloque no es ejecutado y en su lugar se produce una excepción. Aquí está el resultado de este script.

 
/usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:236:in `rescue in establish_connection': Connection refused - Unable to connect to Redis on 127.0.0.1:6379 (Errno::ECONNREFUSED) 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:222:in `establish_connection' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:23:in `connect' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:247:in `ensure_connected' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:137:in `block in process' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:206:in `logging' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:136:in `process' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:46:in `call' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis.rb:246:in `block in keys' 
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize' 
    from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis.rb:245:in `keys' 
    from scripts/redis.rb:11:in `<main>' 

He verificado que Redis.new(:path => "/tmp/redis.sock") funciona como esperaba. He intentado ser más específico con mi bloque de rescate al usar rescue Errno::ECONNREFUSED en vano. No estoy seguro de por qué no puedo ver esta excepción.

¿Alguna idea?

Respuesta

5

Resulta que la excepción no se produce al llamar al Redis.new. La excepción no se lanza hasta que se invoquen ciertos métodos (en este caso, Redis#keys) en el objeto de conexión. Esta función de conexión revisada parece hacer el truco.

require "redis" 

def r 
    begin 
    $redis ||= Redis.new 
    $redis.inspect # needed to know if connection failed 
    rescue 
    $redis = Redis.new(:path => "/tmp/redis.sock") 
    end 
    $redis 
end 
+4

Sé que esto es una respuesta de edad, pero sólo para arrojar un poco de luz sobre por qué sucede esto. La conexión de Redis está cargada de modo perezoso, por lo que no se conectará hasta que haga un primer comando. –

+0

Parece que lo mejor que puedes hacer es llamar a '$ redis.ping'. Como se señala en la otra respuesta, '.inspect' no es lo suficientemente bueno y' .keys' recupera todos los elementos en redis, lo que hace que esperes mucho tiempo (según el número de entradas en redis) Y ocupa una gran cantidad de memoria que no se puede recolectar basura (ya que no está asignado a ninguna variable). – lucke84

2

me encontré con que $redis.inspect en realidad no ejercen la conexión REDIS. Lo reemplacé con $redis.keys y arrojé la excepción correctamente. Tenga en cuenta que me estoy ejecutando en Heroko y que pasa en la variable de entorno . Luego tengo una constante REDIS que uso en toda la aplicación.

En mi config/inicializadores/redis.rb:

uri = URI.parse(ENV['REDISTOGO_URL']) 
begin 
    redis ||= Redis.new(:host => uri.host, :port => uri.port, :password => uri.password) 
    redis.keys # needed to know if connection failed 
    REDIS = redis 
rescue 
    puts("Redis not loaded on #{uri.port}") 
    REDIS = nil 
end 
+0

'$ redis.inspect' podría no ser una buena manera de hacerlo, ya que no todas las gemas redis se conectarán con esta llamada. '$ redis.keys' sin embargo intentará recuperar todas las claves redis, que se ahogarán si tiene una base de datos realmente grande. En su lugar, usaría algo como '$ redis.info' o' $ redis.get ("some-key-that-do-does-or-doesn't-exist") '. Esos comandos seguirán pasándose al servidor redis, sin tratar de recuperar el mundo. –

Cuestiones relacionadas