2011-10-05 2 views
7

Я пытаюсь написать функцию, которая пытается подключиться к Redis, используя настройки TCP по умолчанию, и если это не удается, пытается подключиться к Redis через unix-сокет. Мое намерение состоит в том, чтобы иметь один сценарий подключения, который работает на всех моих системах, некоторые из которых используют 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, заставляя вас ждать loooong time (в зависимости от количества записей в 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-do-or-doesn't-exist») '. Эти команды все равно будут переданы серверу redis, не пытаясь вернуть мир. –

Смежные вопросы