Ruby 派生进程侦听父服务器端口
Ruby spawned process listening on parent server port
我是 运行 fedora 32 上的 puma 服务器 ruby 应用程序。在我的服务器中,由于各种原因,我有一些调用会产生新的长 运行 进程。我遇到了一个问题,我的派生进程在与我的服务器相同的端口上 运行 和 listening。这导致在部署时重新启动我的服务器时出现问题,因为服务器无法启动,因为进程正在侦听所需的端口。这怎么可能?根据我的理解,当我生成一个进程时,它应该具有与父进程完全不同的内存,并且不共享任何文件描述符。我的 spawn 命令很简单
my_pid = Process.spawn(my_cmd, %i[out err] => log_file)
Ruby 版本 2.7.0
编辑:我在我的部署过程和我最初的问题描述中忽略了一些东西,服务器重启并不是真正的拆除并重新启动一个新进程,而是通过向 puma 服务器发送 USR2 信号(如所述 here)
一个快速的解决方法/解决方案是调用 fork
, close Puma's socket within the forked process and then call exec
, which replaces the running process... 但是,此解决方法仅限于 Unix 系统。在 windows 上,您可能可以使用更复杂的方法实现类似的效果。
遗憾的是,我不确定如何关闭 Puma 的监听套接字。或许 this will helps,但更有可能还有其他一些技巧。
我相信我已经找到了造成这种情况的原因。似乎是我使用的 puma restart process 的问题。通过使用 USR2
信号重新启动服务器,它会更改套接字打开的 fd 上的标志。
[me@home puma_testing]$ cat /proc/511620/fdinfo/5
pos: 0
flags: 02000002
mnt_id: 10
[me@home puma_testing]$ kill -s USR2 511620
[me@home puma_testing]$ cat /proc/511620/fdinfo/5
pos: 0
flags: 02
mnt_id: 10
这是在 fedora 32 上使用非常简单的 puma 和 sinatra 设置进行测试的,如下所示:
puma.rb
# frozen_string_literal: true
rackup File.join(File.dirname(File.realpath(__FILE__)), './server.ru')
# https://www.rubydoc.info/gems/puma/Puma/DSL#prune_bundler-instance_method
# This allows us to install new gems with just a phased-restart. Otherwise you
# need to take the master process down each time.
prune_bundler
port 11111
environment 'production'
pidfile File.join(File.dirname(File.realpath(__FILE__)), '../', 'server.pid')
tag 'test'
并且server.ru
像这样
require 'sinatra'
class App < Sinatra::Base
get "/" do
"Hello World!"
end
get "/spawn" do
spawn "sleep 500"
end
end
run App
运行 使用捆绑器 bundle exec puma -C puma.rb
。请注意,您可以使用 /spawn
获取请求来测试在重新启动之前和之后生成新进程,以查看它是否正在使用 lsof -itcp:11111
侦听套接字
我是 运行 fedora 32 上的 puma 服务器 ruby 应用程序。在我的服务器中,由于各种原因,我有一些调用会产生新的长 运行 进程。我遇到了一个问题,我的派生进程在与我的服务器相同的端口上 运行 和 listening。这导致在部署时重新启动我的服务器时出现问题,因为服务器无法启动,因为进程正在侦听所需的端口。这怎么可能?根据我的理解,当我生成一个进程时,它应该具有与父进程完全不同的内存,并且不共享任何文件描述符。我的 spawn 命令很简单
my_pid = Process.spawn(my_cmd, %i[out err] => log_file)
Ruby 版本 2.7.0
编辑:我在我的部署过程和我最初的问题描述中忽略了一些东西,服务器重启并不是真正的拆除并重新启动一个新进程,而是通过向 puma 服务器发送 USR2 信号(如所述 here)
一个快速的解决方法/解决方案是调用 fork
, close Puma's socket within the forked process and then call exec
, which replaces the running process... 但是,此解决方法仅限于 Unix 系统。在 windows 上,您可能可以使用更复杂的方法实现类似的效果。
遗憾的是,我不确定如何关闭 Puma 的监听套接字。或许 this will helps,但更有可能还有其他一些技巧。
我相信我已经找到了造成这种情况的原因。似乎是我使用的 puma restart process 的问题。通过使用 USR2
信号重新启动服务器,它会更改套接字打开的 fd 上的标志。
[me@home puma_testing]$ cat /proc/511620/fdinfo/5
pos: 0
flags: 02000002
mnt_id: 10
[me@home puma_testing]$ kill -s USR2 511620
[me@home puma_testing]$ cat /proc/511620/fdinfo/5
pos: 0
flags: 02
mnt_id: 10
这是在 fedora 32 上使用非常简单的 puma 和 sinatra 设置进行测试的,如下所示:
puma.rb
# frozen_string_literal: true
rackup File.join(File.dirname(File.realpath(__FILE__)), './server.ru')
# https://www.rubydoc.info/gems/puma/Puma/DSL#prune_bundler-instance_method
# This allows us to install new gems with just a phased-restart. Otherwise you
# need to take the master process down each time.
prune_bundler
port 11111
environment 'production'
pidfile File.join(File.dirname(File.realpath(__FILE__)), '../', 'server.pid')
tag 'test'
并且server.ru
像这样
require 'sinatra'
class App < Sinatra::Base
get "/" do
"Hello World!"
end
get "/spawn" do
spawn "sleep 500"
end
end
run App
运行 使用捆绑器 bundle exec puma -C puma.rb
。请注意,您可以使用 /spawn
获取请求来测试在重新启动之前和之后生成新进程,以查看它是否正在使用 lsof -itcp:11111