Ответ 1
Проверьте наличие файла PID демонов (File.exist? ...
). Если он там, то предположим, что он запускает еще запустить его.
Нам нужно использовать delayed_job (или какой-либо другой процессор фонового задания) для запуска заданий в фоновом режиме, но нам не разрешено изменять сценарии загрузки/уровни загрузки на сервере. Это означает, что демон не гарантированно останется доступным, если поставщик перезапустит сервер (так как демон был запущен рецептом capistrano, который запускается только один раз для развертывания).
В настоящее время лучший способ, с помощью которого я могу думать о том, что daemon delayed_job всегда работает, заключается в добавлении инициализатора в наше приложение Rails, которое проверяет, работает ли демон. Если он не работает, инициализатор запускает демона, иначе он просто оставляет его.
Итак, возникает вопрос, как мы обнаруживаем, что демон Delayed_Job запущен изнутри script? (Мы должны иметь возможность запускать демона довольно легко, бит, я не знаю, как обнаружить, если он уже активен).
У кого-нибудь есть идеи?
С уважением, Bernie
Основываясь на ответе ниже, это то, с чем я столкнулся. Просто поставьте его в config/initializers, и все будет установлено:
#config/initializers/delayed_job.rb
DELAYED_JOB_PID_PATH = "#{Rails.root}/tmp/pids/delayed_job.pid"
def start_delayed_job
Thread.new do
`ruby script/delayed_job start`
end
end
def process_is_dead?
begin
pid = File.read(DELAYED_JOB_PID_PATH).strip
Process.kill(0, pid.to_i)
false
rescue
true
end
end
if !File.exist?(DELAYED_JOB_PID_PATH) && process_is_dead?
start_delayed_job
end
Проверьте наличие файла PID демонов (File.exist? ...
). Если он там, то предположим, что он запускает еще запустить его.
Некоторые идеи по очистке: "Начало" не требуется. Вы должны спасти "нет такого процесса", чтобы не запускать новые процессы, когда что-то не так. Спасите "нет такого файла или каталога", чтобы упростить условие.
DELAYED_JOB_PID_PATH = "#{Rails.root}/tmp/pids/delayed_job.pid"
def start_delayed_job
Thread.new do
`ruby script/delayed_job start`
end
end
def daemon_is_running?
pid = File.read(DELAYED_JOB_PID_PATH).strip
Process.kill(0, pid.to_i)
true
rescue Errno::ENOENT, Errno::ESRCH # file or process not found
false
end
start_delayed_job unless daemon_is_running?
Имейте в виду, что этот код не будет работать, если вы начнете работать с несколькими рабочими. И проверьте аргумент "-m" script/delayed_job, который запускает процесс мониторинга вместе с демоном.
Спасибо за решение, поставленное в вопросе (и ответ, который вдохновил его:-)), он работает для меня, даже с несколькими работниками (Rails 3.2.9, Ruby 1.9.3p327).
Меня беспокоит, что я могу забыть перезапустить delayed_job после внесения некоторых изменений в lib, например, заставив меня отлаживать часы, прежде чем это осознать.
Я добавил следующее в мой файл script/rails
, чтобы разрешить выполнение кода, содержащегося в вопросе, каждый раз, когда мы запускаем рельсы, но не каждый раз, когда рабочий запускает:
puts "cleaning up delayed job pid..."
dj_pid_path = File.expand_path('../../tmp/pids/delayed_job.pid', __FILE__)
begin
File.delete(dj_pid_path)
rescue Errno::ENOENT # file does not exist
end
puts "delayed_job ready."
Небольшой недостаток, с которым я столкнулся, заключается в том, что он также вызван с помощью rails generate
, например. Я не тратил много времени на поиск решения для этого, но предложения приветствуются: -)
Обратите внимание: если вы используете единорог, вы можете добавить тот же код в config/unicorn.rb
перед вызовом before_fork
.
- EDITED: Проиграв немного больше с решениями выше, я закончил делать следующее:
Я создал файл script/start_delayed_job.rb
с контентом:
puts "cleaning up delayed job pid..."
dj_pid_path = File.expand_path('../../tmp/pids/delayed_job.pid', __FILE__)
def kill_delayed(path)
begin
pid = File.read(path).strip
Process.kill(0, pid.to_i)
false
rescue
true
end
end
kill_delayed(dj_pid_path)
begin
File.delete(dj_pid_path)
rescue Errno::ENOENT # file does not exist
end
# spawn delayed
env = ARGV[1]
puts "spawing delayed job in the same env: #{env}"
# edited, next line has been replaced with the following on in order to ensure delayed job is running in the same environment as the one that spawned it
#Process.spawn("ruby script/delayed_job start")
system({ "RAILS_ENV" => env}, "ruby script/delayed_job start")
puts "delayed_job ready."
Теперь я могу потребовать этот файл в любом месте, включая "script/rails" и "config/unicorn.rb", выполнив:
# in top of script/rails
START_DELAYED_PATH = File.expand_path('../start_delayed_job', __FILE__)
require "#{START_DELAYED_PATH}"
# in config/unicorn.rb, before before_fork, different expand_path
START_DELAYED_PATH = File.expand_path('../../script/start_delayed_job', __FILE__)
require "#{START_DELAYED_PATH}"
Отказ от ответственности: я говорю не очень, потому что это вызывает периодический перезапуск, что для многих нежелательно. И просто попытка начать может вызвать проблемы, потому что реализация DJ может заблокировать очередь, если созданы дублирующие экземпляры.
Вы можете запланировать задачи cron
, которые периодически запускаются для запуска заданий (задач). Поскольку DJ обрабатывает стартовые команды как no-ops, когда работа уже запущена, она просто работает. Этот подход также учитывает случай, когда DJ умирает по какой-либо причине, кроме перезапуска хоста.
# crontab example
0 * * * * /bin/bash -l -c 'cd /var/your-app/releases/20151207224034 && RAILS_ENV=production bundle exec script/delayed_job --queue=default -i=1 restart'
Если вы используете драгоценный камень, например whenever
, это довольно просто.
every 1.hour do
script "delayed_job --queue=default -i=1 restart"
script "delayed_job --queue=lowpri -i=2 restart"
end