#ruby-on-rails #ruby #ruby-on-rails-6
#ruby-on-rails #ruby #ruby-on-rails-6
Вопрос:
Я хочу запустить процесс 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 amp;")
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, если она запущена, это не так!
Но когда я набираю Ngrok.instance.start
в консоли rails, вот результат:
И это начинается!
Итак, мой вопрос: ПОЧЕМУ, ЧЕРТ system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log amp;")
ВОЗЬМИ, НЕ работает на rails serve, но он находится на консоли rails?
Обновить
Если я использую ‘byebug’ в ngrok.rb и использую rails serve, когда я выхожу из byebug с помощью «continue», процесс ngrok создается и работает
Комментарии:
1. Тот факт, что он работает, когда вы устанавливаете точку останова, заставляет меня думать, что это проблема синхронизации между асинхронными процессами. Попробуйте добавить еще немного сна и посмотреть, что это изменит
2. @maxpleaner уверен. Это то, что я подумал. Я поставил бесчисленное количество спящих мест в бесчисленных местах! Тем не менее, я не думаю, что это проблема, поскольку Ngrok.instance.start работал в rails c, но не в rails s, независимо от внутренних спящих
3. Вы работаете на macOS или Linux или еще?
4. У вас нет проверки ошибок. Используйте
exception: true
или child_process или ручную fork exec с проверкой ошибок.5. @kisch Я использую Linux, Ubuntu 20
Ответ №1:
Вы создаете потерянный процесс так, как вы используете system()
для запуска процесса ngrok в фоновом режиме:
system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log amp;")
Обратите amp;
внимание на конец командной строки.
Мне нужно больше информации о вашей среде выполнения, чтобы точно указать, какая системная политика уничтожает потерянный процесс ngrok сразу после его запуска (какая ОС? если Linux, основан ли он на systemd? как вы запускаете rails server, с терминала или как системную службу?).
Но что происходит, так это:
system()
запускает экземпляр/bin/sh
для интерпретации командной строки/bin/sh
запускает процесс ngrok в фоновом режиме и завершает- ngrok теперь «осиротел», что означает, что его родительский процесс
/bin/sh
завершен, так что процесс ngrok не может бытьwait(2)
отредактирован для - в зависимости от среды завершение
/bin/sh
может убить ngrok сигналом SIGHUP - или ОС повторно запускает ngrok, обычно для процесса инициализации (но это зависит)
Когда вы используете консоль rails или byebug, в обоих случаях вы входите в интерактивную среду, которая подготавливает «группы процессов», «идентификаторы сеансов» и «управляющие терминалы» способом, подходящим для интерактивного выполнения. Эти свойства наследуются дочерними процессами, такими как ngrok. Это влияет на системные политики в отношении обработки потерянного фонового процесса.
При запуске ngrok с rails server эти свойства будут отличаться (в зависимости от способа запуска rails server).
Вот хорошая статья о некоторых механизмах ОС, которые могут быть задействованы: https://www.jstorimer.com/blogs/workingwithcode/7766093-daemon-processes-in-ruby
Вероятно, вы добились бы большего успеха, используя Ruby Process.spawn
для запуска фонового процесса в сочетании с Process.detach
в вашем случае. Это позволит избежать потери процесса ngrok.
Комментарии:
1. Это то, что я подозревал. Ваше понимание очень уместно. Я попробую Process.spawn. На самом деле, что сработало для меня, так это запустить задание CRON @ reboot со временем ожидания 2 минуты. Но я и другие читатели моего вопроса ищут Rails-способ сделать это, и ваши идеи очень помогли! Спасибо!!!
2. Хотя это имеет смысл, в статье здесь говорится, что процессы UNIX принимаются инициализацией при потере. Я посмотрю дальше en.m.wikipedia.org/wiki/Orphan_process