2011-10-05 15 views
7

デフォルトのTCP設定を使用してRedisに接続しようとする機能を作成しようとしていますが、失敗した場合はUnixソケットを介してRedisに接続しようとします。私の意図は、すべての私のシステムで動作する単一の接続スクリプトを用意することです。その中にはTCPを使用するものやソケットを使用するものがあります。Redis接続拒否から救助できません

しかし、私は失敗したTCP接続から救助することはできません。ここに私のテストスクリプトがあります。

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ブロックが実行されず、代わりに例外が発生します。これはこのスクリプトの出力です。

 
/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>' 

私はRedis.new(:path => "/tmp/redis.sock")作品が期待通りにことを確認しました。私はrescue Errno::ECONNREFUSEDを使用して私のレスキューブロックについてより具体的にしようとしました。なぜ私はこの例外をキャッチできないのか分かりません。

アイデア?

答えて

5

Redis.newを呼び出すときに例外がスローされないことが判明しました。この例外は、接続オブジェクトの特定のメソッド(この場合はRedis#keys)が呼び出されるまでスローされません。この改訂された接続機能は、このトリックを行うように見えます。

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

私は、これは古い答えです知っているが、ちょうどそれがなぜ起こるかに光のビットを当てること。 Redis接続は遅延ロードされているため、最初のコマンドを実行するまで接続しません。 –

+0

あなたができる最良のものは '$ redis.ping'です。他の答えで指摘されているように、 '.inspect'は十分ではなく、' .keys'はredisのすべての項目を取得するので、(redisの項目数に依存して)長い時間待つことになり、ガベージコレクションできません(変数に割り当てられていないため)。 – lucke84

2

私は$redis.inspectが実際にREDIS接続を行使しなかったことがわかりました。私はそれを$redis.keysと置き換え、それは正しく例外を投げた。注意してください。Herokoを実行しており、環境変数を渡しています。私はその後、私がアプリケーションを通して使用する一定のREDISを持っています。私の設定/初期化子/ 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'は、すべてのredisの宝石がこの呼び出しに接続するわけではないので、それを行うには良い方法ではないかもしれません。 '$ redis.keys'はすべてのredisキーを取得しようとします。本当に大きなデータベースを持っている場合には、それは枯渇します。代わりに、 '$ redis.info'や' $ redis.get( "some-key-that-does-does-does-doesn't-exist") 'のようなものを使用します。これらのコマンドは、世界を復帰させようとせずに、引き続き赤いサーバに渡されます。 –

関連する問題