2011-10-05 17 views
7

Sto tentando di scrivere una funzione che tenta di connettersi a Redis utilizzando le impostazioni TCP predefinite e, in caso di esito negativo, tenta di connettersi a Redis tramite un socket unix. Il mio intento è di avere un singolo script di connessione che funzioni su tutti i miei sistemi, alcuni dei quali usano TCP e altri che usano socket.Impossibile eseguire il ripristino dal rifiuto della connessione di Redis

Tuttavia, non riesco a recuperare dalla connessione TCP fallita. Ecco il mio script di test.

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" 

Il blocco rescue non viene mai eseguito e invece viene generata un'eccezione. Ecco l'output di questo 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>' 

Ho verificato che Redis.new(:path => "/tmp/redis.sock") funziona come previsto. Ho cercato di essere più specifico con il mio blocco di salvataggio utilizzando rescue Errno::ECONNREFUSED inutilmente. Non sono sicuro del motivo per cui non riesco a cogliere questa eccezione.

Qualche idea?

risposta

5

Si scopre che l'eccezione non viene generata quando si chiama Redis.new. L'eccezione non viene generata finché non vengono chiamati determinati metodi (in questo caso, Redis#keys) sull'oggetto di connessione. Questa funzione di connessione rivista sembra fare il trucco.

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

So che questa è una risposta vecchia, ma solo a spargere un po 'di luce sul motivo per cui questo accade. La connessione di Redis è pigra, quindi non ti connetteresti finché non eseguirai un primo comando. –

+0

Sembra che la cosa migliore che puoi fare è chiamare '$ redis.ping'. Come sottolineato nell'altra risposta, '.inspect' non è abbastanza buono e' .keys' recupera tutti gli elementi in redis, facendoti aspettare un tempo mooolto (a seconda del numero di voci in redis) e occupando molta memoria che non può essere garbage collection (dato che non è assegnato a nessuna variabile). – lucke84

2

ho scoperto che $redis.inspect non ha in realtà esercitare la connessione REDIS. L'ho sostituito con $redis.keys e quello ha gettato correttamente l'eccezione. Nota, sto funzionando su Heroko e passa nella variabile di ambiente . Ho quindi una costante REDIS che uso in tutta l'applicazione.

Nel mio config/inizializzatori/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' potrebbe non essere un buon modo per farlo in quanto non tutte le gemme redis si connetteranno con questa chiamata. '$ redis.keys', sebbene proverà a recuperare tutte le chiavi redis, che si strozzeranno se si dispone di un database molto grande. Vorrei invece usare qualcosa come '$ redis.info' o' $ redis.get ("some-key-that-does-or-doesn't-exist") '. Questi comandi saranno comunque passati al server redis, senza cercare di riportare il mondo. –

Problemi correlati