Rails: 系统进程不会在 rails 服务器中启动,但会在 rails 控制台中启动
Rails: system process won't start in rails server, but will in rails console
我想在服务器启动时启动一个 ngrok 进程。为此,我编写了一个 ngrok.rb 库,并在初始化程序
中调用它
app/lib/ngrok.rb
require "singleton"
class Ngrok
include Singleton
attr_accessor :api_url, :front_url
def start
if is_running?
return fetch_urls
end
authenticate
started = system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log &")
system("sleep 1")
if !started
return { api: nil, front: nil }
end
urls = fetch_urls
sync_urls(urls["api_url"], urls["front_url"])
return urls
end
def sync_urls(api_url, front_url)
NgrokSyncJob.perform_later(api_url, front_url)
end
def is_running?
return system("ps aux | grep ngrok")
end
def restart
stop
return start
end
def stop
return system("pkill ngrok")
end
def authenticate
has_file = system("ls ~/.ngrok2/ngrok.yml")
if has_file
return true
else
file_created = system("ngrok authtoken #{ENV['NGROK_TOKEN']}")
if file_created
return system("cat " + ENV['APP_ROOT'] + '/essentials/ngrok/example.yml >> ~/.ngrok2/ngrok.yml')
else
return false
end
end
end
def fetch_urls
logfile = ENV['APP_ROOT'] + '/log/ngrok.log'
file = File.open logfile
text = file.read
api_url = nil
front_url = nil
text.split("\n").each do |line|
next if !line.include?("url=") || !line.include?("https")
if line.split("name=")[1].split(" addr=")[0] == "ncommerce-api"
api_url = line.split("url=")[1]
elsif line.split("name=")[1].split(" addr=")[0] == "ncommerce"
front_url = line.split("url=")[1]
end
end
file.close
self.api_url = api_url
self.front_url = front_url
res = {}
res["api_url"] = api_url
res["front_url"] = front_url
return res
end
end
config/initializers/app-init.rb
module AppModule
class Application < Rails::Application
config.after_initialize do
puts "XXXXXXXXXXXXXXXXXXXXXXX"
Ngrok.instance.start
puts "XXXXXXXXXXXXXXXXXXXXXXX"
end
end
end
当我键入 rails serve 时,这里是输出示例
所以我们肯定知道我的初始化程序被调用了,但是当我查看 rails 控制台时,如果它是 运行,它不是!
但是当我在 rails 控制台中输入 Ngrok.instance.start
时,输出如下:
开始了!
所以,我的问题是:为什么地球上 system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log &")
没有在 rails 服务上运行,但它在 rails 控制台上运行?
更新
如果我在 ngrok.rb 中使用 'byebug' 并使用 rails 服务,当我使用“continue”退出 byebug 时,ngrok 进程被创建并运行
您正在创建一个孤立进程,其方式与您使用system()
在后台启动 ngrok 进程的方式相同:
system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log &")
注意命令行末尾的 &
。
我需要有关您的运行时环境的更多详细信息,以便准确地告诉 哪个 系统策略在启动后立即杀死孤立的 ngrok 进程(哪个 OS?如果 Linux,它是基于 systemd 的吗?如何启动 rails 服务器,从终端还是作为系统服务?)。
但实际情况是这样的:
system()
启动一个 /bin/sh
的实例来解释命令行
/bin/sh
在后台启动ngrok进程并终止
- ngrok 现在是“孤立的”,这意味着它的父进程
/bin/sh
已终止,因此 ngrok 进程无法 wait(2)
ed 为
- 根据环境,终止
/bin/sh
可能会用 SIGHUP 信号杀死 ngrok
- 或 OS re-parents ngrok,通常为 init-process(但这取决于)
当您使用 rails 控制台或 byebug 时,在这两种情况下您都进入了一个交互式环境,它以适合的方式准备“进程组”、“会话 ID”和“控制终端”交互式执行。这些属性由子进程继承,例如 ngrok。这会影响有关处理孤立后台进程的系统策略。
当 ngrok 从 rails 服务器启动时,这些属性会有所不同(取决于 rails 服务器的启动方式)。
这是一篇关于可能涉及的一些 OS 机制的好文章:https://www.jstorimer.com/blogs/workingwithcode/7766093-daemon-processes-in-ruby
如果使用 Ruby 的 Process.spawn
启动后台进程,在您的情况下结合 Process.detach
,您可能会取得更好的成功。这将避免孤立 ngrok 进程。
我想在服务器启动时启动一个 ngrok 进程。为此,我编写了一个 ngrok.rb 库,并在初始化程序
中调用它app/lib/ngrok.rb
require "singleton"
class Ngrok
include Singleton
attr_accessor :api_url, :front_url
def start
if is_running?
return fetch_urls
end
authenticate
started = system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log &")
system("sleep 1")
if !started
return { api: nil, front: nil }
end
urls = fetch_urls
sync_urls(urls["api_url"], urls["front_url"])
return urls
end
def sync_urls(api_url, front_url)
NgrokSyncJob.perform_later(api_url, front_url)
end
def is_running?
return system("ps aux | grep ngrok")
end
def restart
stop
return start
end
def stop
return system("pkill ngrok")
end
def authenticate
has_file = system("ls ~/.ngrok2/ngrok.yml")
if has_file
return true
else
file_created = system("ngrok authtoken #{ENV['NGROK_TOKEN']}")
if file_created
return system("cat " + ENV['APP_ROOT'] + '/essentials/ngrok/example.yml >> ~/.ngrok2/ngrok.yml')
else
return false
end
end
end
def fetch_urls
logfile = ENV['APP_ROOT'] + '/log/ngrok.log'
file = File.open logfile
text = file.read
api_url = nil
front_url = nil
text.split("\n").each do |line|
next if !line.include?("url=") || !line.include?("https")
if line.split("name=")[1].split(" addr=")[0] == "ncommerce-api"
api_url = line.split("url=")[1]
elsif line.split("name=")[1].split(" addr=")[0] == "ncommerce"
front_url = line.split("url=")[1]
end
end
file.close
self.api_url = api_url
self.front_url = front_url
res = {}
res["api_url"] = api_url
res["front_url"] = front_url
return res
end
end
config/initializers/app-init.rb
module AppModule
class Application < Rails::Application
config.after_initialize do
puts "XXXXXXXXXXXXXXXXXXXXXXX"
Ngrok.instance.start
puts "XXXXXXXXXXXXXXXXXXXXXXX"
end
end
end
当我键入 rails serve 时,这里是输出示例
所以我们肯定知道我的初始化程序被调用了,但是当我查看 rails 控制台时,如果它是 运行,它不是!
但是当我在 rails 控制台中输入 Ngrok.instance.start
时,输出如下:
开始了!
所以,我的问题是:为什么地球上 system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log &")
没有在 rails 服务上运行,但它在 rails 控制台上运行?
更新
如果我在 ngrok.rb 中使用 'byebug' 并使用 rails 服务,当我使用“continue”退出 byebug 时,ngrok 进程被创建并运行
您正在创建一个孤立进程,其方式与您使用system()
在后台启动 ngrok 进程的方式相同:
system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log &")
注意命令行末尾的 &
。
我需要有关您的运行时环境的更多详细信息,以便准确地告诉 哪个 系统策略在启动后立即杀死孤立的 ngrok 进程(哪个 OS?如果 Linux,它是基于 systemd 的吗?如何启动 rails 服务器,从终端还是作为系统服务?)。
但实际情况是这样的:
system()
启动一个/bin/sh
的实例来解释命令行/bin/sh
在后台启动ngrok进程并终止- ngrok 现在是“孤立的”,这意味着它的父进程
/bin/sh
已终止,因此 ngrok 进程无法wait(2)
ed 为 - 根据环境,终止
/bin/sh
可能会用 SIGHUP 信号杀死 ngrok - 或 OS re-parents ngrok,通常为 init-process(但这取决于)
当您使用 rails 控制台或 byebug 时,在这两种情况下您都进入了一个交互式环境,它以适合的方式准备“进程组”、“会话 ID”和“控制终端”交互式执行。这些属性由子进程继承,例如 ngrok。这会影响有关处理孤立后台进程的系统策略。
当 ngrok 从 rails 服务器启动时,这些属性会有所不同(取决于 rails 服务器的启动方式)。
这是一篇关于可能涉及的一些 OS 机制的好文章:https://www.jstorimer.com/blogs/workingwithcode/7766093-daemon-processes-in-ruby
如果使用 Ruby 的 Process.spawn
启动后台进程,在您的情况下结合 Process.detach
,您可能会取得更好的成功。这将避免孤立 ngrok 进程。