5

我在 Rails 应用程序中使用全局变量来存储使用redis gem的 redis 客户端。在 aconfig/initializers/redis.rb中,我有

$redis = Redis.new(host: "localhost", port: 6379)

然后在应用程序代码中,我$redis用来处理 Redis 存储中的数据。

我还在生产环境中使用puma作为 Web 服务器,并使用 capistrano 来部署代码。在部署过程中,capistrano 重启 puma。

每次我启动或重新启动 puma web 服务器时,当我第一次使用$redis访问 Redis 存储中的数据时,总是会收到“内部服务器错误”。我看到了类似的错误Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.)

用 google 和 stackoverflow 搜索让我认为在 puma fork 子进程之后我需要重新连接到 Redis。所以,我在我的添加config/puma.rb

on_worker_boot do
  $redis.ping
end

但我仍然收到由Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.).

我看到这篇文章http://qiita.com/yaotti/items/18433802bf1720fc0c53。然后我尝试添加config/puma.rb

on_restart do
  $redis.quit
end

那没有用。

我试着config/initializers/redis.rb$redis.ping之后Redis.new。那也没有用。

如果 puma 在没有运行 puma 进程的情况下启动,或者在运行 puma 进程的实例时重新启动,我会收到此错误。

刷新页面会让我克服这个错误。但即使在第一次尝试使用$redis. 我在想我没有使用redisgem 或正确配置它的重新连接。有人可以告诉我:

  1. 这是在 Rails 应用程序中使用redisgem 的正确方法吗?
  2. 应该如何redis重新连接puma

pumagem 文档说,“你应该在这个块中放置关闭全局日志文件、redis 连接等的代码,这样它们的文件描述符就不会泄漏到重新启动的进程中。否则将导致描述符慢慢耗尽并最终由于服务器多次重新启动,因此出现了模糊的崩溃。” 这是在谈论on_restart街区。但它没有说明应该如何做。

4

5 回答 5

2

我能够用猴子补丁修复错误。这会改变行为,因此它只是重新连接而不是抛出Redis::InheritedError

###### MONKEYPATCH redis-rb 
# https://github.com/redis/redis-rb/issues/364
# taken from https://github.com/redis/redis-rb/pull/389/files#diff-597c124889a64c18744b52ef9687c572R314
class Redis
  class Client
   def ensure_connected
      tries = 0

      begin
        if connected?
          if Process.pid != @pid
            reconnect
          end
        else
          connect
        end

        tries += 1

        yield
      rescue ConnectionError
        disconnect

        if tries < 2 && @reconnect
          retry
        else
          raise
        end
      rescue Exception
        disconnect
        raise
      end
    end
  end
end
## MONKEYPATCH end
于 2013-12-12T11:50:29.940 回答
1

我正在使用 Puma 在集群模式下运行带有 IdentityCache 的 Rails 应用程序,worker=4。

重新连接必须在on_worker_boot回调中发生。

我必须重新连接 Rails.cache 和 IdentityCache 以避免重新启动错误。这是我的工作:

puma-config.rb

on_worker_boot do
   puts 'On worker boot...'
   puts "Reconnecting Rails.cache"
   Rails.cache.reconnect
   begin
      puts "Reconnecting IdentityCache"
      IdentityCache.cache.cache_backend.reconnect
   rescue Exception => e
      puts "Error trying to reconnect identity_cache_store: #{e.message}"
   end
end

然后我在日志中看到以下内容,向我展示了一切正常的证据。

On worker boot...
Reconnecting Rails.cache
Reconnecting IdentityCache
On worker boot...
Reconnecting Rails.cache
Reconnecting IdentityCache
On worker boot...
Reconnecting Rails.cache
Reconnecting IdentityCache
On worker boot...
Reconnecting Rails.cache
Reconnecting IdentityCache
[7109] - Worker 7115 booted, phase: 0
[7109] - Worker 7123 booted, phase: 0
[7109] - Worker 7119 booted, phase: 0
[7109] - Worker 7127 booted, phase: 0

果然,以前服务器重启后出现的第一个请求问题都没有了。QED。

于 2014-04-01T02:37:24.983 回答
0

这是我所做的:

  Redis.current.client.reconnect
  $redis = Redis.current

($redis 是我的 redis 客户端的全局实例)

于 2013-09-24T19:35:25.060 回答
0

我已将此放入我的config/puma.rb文件中,对我有用。

on_restart do
  $redis = DiscourseRedis.new
  Discourse::Application.config.cache_store.reconnect
end
on_worker_boot do
  $redis = DiscourseRedis.new
  Discourse::Application.config.cache_store.reconnect
end
于 2014-02-14T11:07:22.590 回答
0
  1. 将redis-rb升级到 3.1.0 或更高版本。详情https://github.com/redis/redis-rb/pull/414/files#
  2. 猴子补丁
# https://github.com/redis/redis-rb/pull/414/files#diff-5bc007010e6c2e0aa70b64d6f87985c20986ee1b2882b63a89b52659ee9c91f8
class Redis
  class Client
    def ensure_connected
      tries = 0
      begin
        if connected?
          if Process.pid != @pid
            raise InheritedError,
              "Tried to use a connection from a child process without reconnecting. " +
              "You need to reconnect to Redis after forking."
          end
        else
          connect
        end
        tries += 1

        yield
      rescue ConnectionError, InheritedError
        disconnect

        if tries < 2 && @reconnect
          retry
        else
          raise
        end
      rescue Exception
        disconnect
        raise
      end
    end
  end
end
于 2021-11-27T08:27:21.417 回答