【问题标题】:Unable to rescue from Redis connection refusal无法从 Redis 连接拒绝中挽救
【发布时间】:2011-12-01 06:06:15
【问题描述】:

我正在尝试编写一个尝试使用默认 TCP 设置连接到 Redis 的函数,如果失败,则尝试通过 unix 套接字连接到 Redis。我的目的是让一个连接脚本适用于我的所有系统,其中一些使用 TCP,而另一些使用套接字。

但是,我似乎无法从失败的 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 inestablish_connection':连接被拒绝 - 无法连接到 Redis在 127.0.0.1:6379 (Errno::ECONNREFUSED) 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:222:in `建立连接' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:23:in `connect' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:247:in `ensure_connected' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:137:in `block in process' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:206:in `logging' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:136:in `process' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis/client.rb:46:in `call' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis.rb:246:in `block in keys' 来自 /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize' 来自 /usr/local/rvm/gems/ruby-1.9.2-p290/gems/redis-2.2.2/lib/redis.rb:245:in `keys' 来自脚本/redis.rb:11:in `
'

我已验证 Redis.new(:path => "/tmp/redis.sock") 可以按预期工作。我试图通过使用rescue Errno::ECONNREFUSED 来更具体地使用我的救援块,但无济于事。我不知道为什么我不能捕捉到这个异常。

有什么想法吗?

【问题讨论】:

    标签: ruby redis


    【解决方案1】:

    原来调用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
    

    【讨论】:

    • 我知道这是一个旧的答案,但只是为了说明为什么会发生这种情况。 Redis 连接是延迟加载的,因此在您发出第一个命令之前不会连接。
    • 似乎您能做的最好的事情就是致电$redis.ping。正如另一个答案中所指出的,.inspect 不够好,.keys 检索redis 中的所有项目,让您等待很长时间(取决于redis 中的条目数)并占用大量内存t 被垃圾收集(因为它没有分配给任何变量)。
    【解决方案2】:

    我发现$redis.inspect 实际上并没有使用REDIS 连接。我用$redis.keys 替换了它,并且正确地抛出了异常。注意,我在Heroko 上运行,它传入环境变量REDISTOGO_URL。然后我有一个常量REDIS,我会在整个应用程序中使用它。

    在我的 config/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
    

    【讨论】:

    • $redis.inspect 可能不是一个好方法,因为并非所有 redis gem 都会与此调用连接。 $redis.keys 虽然会尝试检索所有 redis 键,但如果你有一个非常大的数据库,这将会窒息。我会改用$redis.info$redis.get("some-key-that-does-or-doesn't-exist") 之类的东西。这些命令仍将传递给 redis 服务器,而不会尝试恢复世界。
    猜你喜欢
    • 2011-06-07
    • 2013-01-18
    • 2019-02-04
    • 2021-01-24
    • 2021-09-18
    • 2017-07-10
    • 2016-02-14
    • 2020-06-28
    • 2022-01-16
    相关资源
    最近更新 更多