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

Нам нужно использовать 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

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

не очень, но работает

Отказ от ответственности: я говорю не очень, потому что это вызывает периодический перезапуск, что для многих нежелательно. И просто попытка начать может вызвать проблемы, потому что реализация 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