2011-10-05 55 views
7

Tôi đang cố gắng để viết một chức năng mà cố gắng để kết nối với Redis sử dụng cài đặt TCP mặc định, và nếu thất bại, cố gắng để kết nối với Redis thông qua một ổ cắm unix. Mục đích của tôi là có một kịch bản kết nối duy nhất hoạt động trên tất cả các hệ thống của tôi, một số trong đó sử dụng TCP và các hệ thống khác sử dụng ổ cắm.Không thể giải cứu từ Redis kết nối từ chối

Tuy nhiên, tôi dường như không thể giải cứu từ các kết nối TCP thất bại. Đây là kịch bản thử nghiệm của tôi.

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" 

Khối rescue không bao giờ được thực thi và thay vào đó là ngoại lệ. Đây là đầu ra của tập lệnh này.

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

Tôi đã xác minh rằng Redis.new(:path => "/tmp/redis.sock") hoạt động như mong đợi. Tôi đã cố gắng cụ thể hơn với khối cứu hộ của mình bằng cách sử dụng rescue Errno::ECONNREFUSED để không có kết quả. Tôi không chắc tại sao tôi không thể bắt được ngoại lệ này.

Bất kỳ ý tưởng nào?

Trả lời

5

Nó chỉ ra các ngoại lệ không được ném khi gọi Redis.new. Ngoại lệ không bị ném cho đến khi một số phương thức nhất định (trong trường hợp này là Redis#keys) trên đối tượng kết nối được gọi. Chức năng kết nối được sửa đổi này xuất hiện để thực hiện thủ thuật.

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

Tôi biết đây là một câu trả lời cũ nhưng chỉ để đổ một chút ánh sáng về lý do tại sao điều đó xảy ra. Redis kết nối là lười biếng nạp, vì vậy bạn sẽ không kết nối cho đến khi bạn thực hiện một lệnh đầu tiên. –

+0

Có vẻ như điều tốt nhất bạn có thể làm là gọi '$ redis.ping'. Như đã chỉ ra trong câu trả lời khác, '.inspect' không đủ tốt và' .keys' truy xuất tất cả các mục bằng redis, làm cho bạn chờ một thời gian dài (tùy thuộc vào số mục nhập trong redis) VÀ chiếm rất nhiều bộ nhớ không thể thu gom rác (vì nó không được gán cho bất kỳ biến nào). – lucke84

2

tôi thấy rằng $redis.inspect không thực sự thực hiện kết nối REDIS. Tôi đã thay thế nó bằng $redis.keys và điều đó đã loại bỏ một cách chính xác ngoại lệ. Lưu ý, đang chạy trên Heroko và nó đi trong môi trường biến . Sau đó tôi có một hằng số REDIS mà tôi sử dụng trong suốt ứng dụng.

Trong cấu hình của tôi/initializers/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' có thể không phải là một cách tốt để làm điều đó vì không phải tất cả đá quý redis sẽ kết nối với cuộc gọi này. '$ redis.keys' mặc dù sẽ cố gắng lấy lại tất cả các phím redis, mà sẽ bị sặc nếu bạn có một cơ sở dữ liệu thực sự lớn. Thay vào đó, tôi sẽ sử dụng một cái gì đó như '$ redis.info' hoặc' $ redis.get ("some-key-that-does-does-or-does-exist") '. Những lệnh này sẽ vẫn được chuyển đến máy chủ redis, mà không cố gắng mang lại thế giới. –

Các vấn đề liên quan