在Puma fork之后重新连接Redis

时间:2013-09-10 13:45:57

标签: ruby-on-rails redis puma

我在rails应用程序中使用全局变量来使用redis gem存储redis客户端。在config/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 forks进程后重新连接到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.pingRedis.new。这也不起作用。

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

刷新页面会让我超过此错误。但我想在第一次尝试使用$redis时摆脱这种情况。我以为我没有使用redis gem或正确配置其重新连接。有人能告诉我:

  1. 这是在rails应用程序中使用redis gem的正确方法吗?
  2. 如何在redis中重新连接puma连接?
  3. puma gem文档说,“您应该放置代码来关闭此块中的全局日志文件,redis连接等,以便它们的文件描述符不会泄漏到重新启动的进程中。否则将导致在服务器多次重启时,慢慢耗尽描述符并最终模糊崩溃。“它在谈论on_restart块。但它没有说明应该怎么做。

4 个答案:

答案 0 :(得分:2)

我能够使用monkeypatch修复错误。这会改变行为,因此它只是重新连接而不是抛出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

答案 1 :(得分:1)

我在群集模式下使用Puma运行带有IdentityCache的Rails应用程序,其中workers = 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。

答案 2 :(得分:0)

这就是我的所作所为:

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

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

答案 3 :(得分: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