Запустите или убедитесь, что отложенное задание запускается при перезапуске приложения / сервера - PullRequest
11 голосов
/ 06 апреля 2010

Мы должны использовать delayed_job (или какой-либо другой процессор фоновых заданий) для запуска заданий в фоновом режиме, но мы не можем изменять сценарии загрузки / уровни загрузки на сервере. Это означает, что демон не гарантированно останется доступным, если провайдер перезапустит сервер (поскольку демон был бы запущен по рецепту capistrano, который запускается только один раз за развертывание).

В настоящее время лучший способ убедиться, что демон delayed_job всегда запущен, - это добавить инициализатор в наше приложение Rails, которое проверяет, запущен ли демон. Если он не запущен, то инициализатор запускает демон, в противном случае он просто оставляет его.

Следовательно, вопрос в том, как мы можем обнаружить, что демон Delayed_Job работает изнутри скрипта? (Мы должны довольно легко запустить демон, но я не знаю, как определить, активен ли он уже).

У кого-нибудь есть идеи?

С уважением, Bernie

Исходя из ответа ниже, это то, что я придумал. Просто поместите его в config / initializer, и все готово:

#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

Ответы [ 4 ]

9 голосов
/ 14 декабря 2010

Еще несколько идей по уборке: «начинать» не нужно. Вы должны спасти "нет такого процесса", чтобы не запускать новые процессы, когда что-то пойдет не так. Спасите также «нет такого файла или каталога», чтобы упростить условие.

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, который порождает процесс мониторинга вместе с демонами.

5 голосов
/ 06 апреля 2010

Проверить наличие файла PID демона (File.exist? ...). Если он есть, тогда предположите, что он работает, иначе запустите его.

0 голосов
/ 11 декабря 2015

не отлично, но работает

заявление об отказе: я говорю, что это плохо, потому что это вызывает периодический перезапуск, который для многих нежелателен А простая попытка запуска может вызвать проблемы, потому что реализация DJ может заблокировать очередь, если создаются дублированные экземпляры.

Вы можете запланировать cron задач, которые периодически запускаются, для запуска заданий. Поскольку диджей обрабатывает команды пуска как неактивные, когда задание уже выполняется, оно просто работает. Этот подход также учитывает случай, когда 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
0 голосов
/ 22 февраля 2013

Спасибо за решение, предоставленное в вопросе (и ответ, который вдохновил его :-)), он работает для меня, даже с несколькими работниками (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 call.

- РЕДАКТИРОВАНИЕ: Поработав с приведенными выше решениями, я сделал следующее:

Я создал файл 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}"
...