Запустите или убедитесь, что отложенное задание запускается при перезапуске приложения / сервера

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

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

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

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

С уважением, Берни

Основываясь на ответе ниже, я пришел к следующему. Просто поместите его в 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

person btelles    schedule 05.04.2010    source источник
comment
Разве в вашем ответе не следует также указать -e production?   -  person nathanvda    schedule 14.09.2010
comment
Используя rails3, это решение не работает для меня. Запуск процесса идет совершенно неправильно: он продолжает запускать дополнительные задания. Я вернулся к задачам capistrano :)   -  person nathanvda    schedule 14.09.2010
comment
Для Rails 4+ вы должны заменить script/delayed_job на bin/delayed_job внутри метода start_delayed_job   -  person Brian Hellekin    schedule 24.07.2018


Ответы (4)


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

person Tony Fontenot    schedule 05.04.2010
comment
Здорово! Звучит просто! Не могли бы вы найти этот файл? - person btelles; 06.04.2010
comment
Вы найдете файл в папке tmp / pids вашего приложения. Вы также можете проверить, существует ли процесс с идентификатором из файла. Файл PID может все еще существовать после сбоя. - person Tomas Markauskas; 06.04.2010
comment
Отлично! Спасибо! Я сейчас проголосую за и подожду, чтобы посмотреть, есть ли другие альтернативы в течение дня или двух. - person btelles; 06.04.2010
comment
Вам нужно найти файл PID и, если в таблице процессов существует запись с этим идентификатором, И, вероятно, также проверьте, что у нее правильное имя. Вполне возможно, что первые два теста будут истинными, если процесс с этим идентификатором не будет тем, который ожидается, если система неожиданно выйдет из строя, оставив устаревший файл PID. Возможно, более быстрый способ проверить - это заставить процесс демона ответить на какой-то запрос пульса. Отправьте запрос, и если вы получите правильный ответ, значит, нужный вам код запущен. В этом случае проверка файла PID действительно не нужна. - person the Tin Man; 07.04.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» сценария / delayed_job, который запускает процесс монитора вместе с демоном (ами).

person Svoop    schedule 14.12.2010

Спасибо за решение, представленное в вопросе (и ответ, который вдохновил его :-)), оно работает для меня, даже с несколькими рабочими (Rails 3.2.9, Ruby 1.9.3p327).

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

Я добавил следующее в свой script/rails файл, чтобы код, указанный в вопросе, выполнялся каждый раз, когда мы запускаем 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.

- ИЗМЕНИТЬ: немного поэкспериментировав с приведенными выше решениями, я сделал следующее:

Я создал файл 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}"
person Abdo    schedule 22.02.2013

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

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

Вы можете запланировать cron задачи, которые периодически запускаются для запуска рассматриваемых заданий. Поскольку DJ рассматривает команды запуска как запретные операции, когда задание уже выполняется, он просто работает. Этот подход также учитывает случай, когда 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
person Shyam Habarakada    schedule 11.12.2015