我在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.ping
到Redis.new
。这也不起作用。
如果puma在没有运行puma进程的情况下启动,或者在puma进程实例运行时重新启动,则会出现此错误。
刷新页面会让我超过此错误。但我想在第一次尝试使用$redis
时摆脱这种情况。我以为我没有使用redis
gem或正确配置其重新连接。有人能告诉我:
redis
gem的正确方法吗?redis
中重新连接puma
连接? puma
gem文档说,“您应该放置代码来关闭此块中的全局日志文件,redis连接等,以便它们的文件描述符不会泄漏到重新启动的进程中。否则将导致在服务器多次重启时,慢慢耗尽描述符并最终模糊崩溃。“它在谈论on_restart
块。但它没有说明应该怎么做。
答案 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