[英]Reconnect with Redis after Puma fork
I am using a global variable in a rails application to store a redis client using the redis gem .我在 rails 应用程序中使用全局变量来存储使用redis gem的 redis 客户端。 In a
config/initializers/redis.rb
, I have在
config/initializers/redis.rb
,我有
$redis = Redis.new(host: "localhost", port: 6379)
Then in application code, I use $redis
to work the data in the Redis store.然后在应用程序代码中,我使用
$redis
来处理 Redis 存储中的数据。
I also use puma as the web server in production environment, and capistrano to deploy code.我也在生产环境中使用puma作为 web 服务器,使用 capistrano 来部署代码。 In the deploy process, capistrano restarts puma.
在部署过程中,capistrano 会重启 puma。
Every time I start or restart the puma web servers, I always get an "Internal Server Error" when I first use $redis
to access data in the Redis store.每次启动或重新启动 puma Web 服务器时,当我第一次使用
$redis
访问 Redis 存储中的数据时,总是会出现“内部服务器错误”。 I saw errors like Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.)
我看到了像
Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.)
这样的错误Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.)
Searching around with google and stackoverflow led me to think that I needed to reconnect to Redis after puma forks child processes.使用 google 和 stackoverflow 四处搜索让我认为在 puma 分叉子进程后我需要重新连接到 Redis。 So, I added in my
config/puma.rb
:所以,我在我的
config/puma.rb
添加:
on_worker_boot do
$redis.ping
end
But I was still getting the "Internal Server Error" caused by Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.)
.但是我仍然收到由
Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.)
引起的“内部服务器错误” Redis::InheritedError (Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.)
。
I saw this post http://qiita.com/yaotti/items/18433802bf1720fc0c53 .我看到了这个帖子http://qiita.com/yaotti/items/18433802bf1720fc0c53 。 I then tried adding in
config/puma.rb
:然后我尝试添加
config/puma.rb
:
on_restart do
$redis.quit
end
That did not work.那没有用。
I tried in config/initializers/redis.rb
to $redis.ping
right after Redis.new
.我在
config/initializers/redis.rb
尝试在$redis.ping
之后Redis.new
到$redis.ping
Redis.new
。 That did not work either.那也没有用。
I got this error if puma was started with no puma processes running, or restarted when an instance of puma process was running.如果 puma 在没有运行 puma 进程的情况下启动,或者在 puma 进程的实例运行时重新启动,我会收到此错误。
Refreshing the page would get me past this error.刷新页面会让我克服这个错误。 But I want to get rid of this even on the first attempt to use
$redis
.但即使在第一次尝试使用
$redis
我也想摆脱这个。 I was thinking that I did not use the redis
gem or configure its reconnection correctly.我在想我没有使用
redis
gem 或正确配置它的重新连接。 Could someone tell me:谁能告诉我:
redis
gem in a rails application?redis
gem 的正确方法吗?redis
connection be reconnected in puma
?puma
redis
连接应该如何重新连接? puma
gem documentation says, "You should place code to close global log files, redis connections, etc in this block so that their file descriptors don't leak into the restarted process. Failure to do so will result in slowly running out of descriptors and eventually obscure crashes as the server is restart many times." puma
gem 文档说,“你应该在这个块中放置代码来关闭全局日志文件、redis 连接等,这样它们的文件描述符就不会泄漏到重新启动的进程中。否则将导致描述符慢慢耗尽,由于服务器多次重启,最终模糊了崩溃。” It was talking about the on_restart
block.它在谈论
on_restart
块。 But it did not say how that should be done.但它没有说明应该如何做。
I was able to fix the error with a monkeypatch. 我能用monkeypatch修复错误。 This changes the behaviour so it just reconnects instead of throwing the
Redis::InheritedError
这会改变行为,因此它只是重新连接而不是抛出
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
I'm running a Rails Application with IdentityCache using Puma in clustered mode with workers=4. 我在集群模式下使用Puma运行带有IdentityCache的Rails应用程序,其中workers = 4。
It is essential that the reconnects happen in the on_worker_boot callback. 重新连接必须在on_worker_boot回调中发生。
I have to reconnect both the Rails.cache and the IdentityCache to avoid restart errors. 我必须重新连接Rails.cache和IdentityCache以避免重启错误。 Here's what I got working:
这就是我的工作:
puma-config.rb 彪马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
Then I see the following in my logs, showing me the proof that it all works. 然后我在日志中看到以下内容,向我展示了一切正常的证明。
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
Sure enough, the first request problems that used to be there after server restart are gone. 果然,服务器重启后的第一个请求问题就消失了。 QED.
QED。
Here's what I did: 这是我做的:
Redis.current.client.reconnect
$redis = Redis.current
($redis is my global instance of a redis client) ($ redis是我的redis客户端的全局实例)
I've put this into my config/puma.rb
file, works for me. 我把它放到我的
config/puma.rb
文件中,对我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
# 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.