Pergunta

Temos que usar o time_job (ou algum outro processador de trabalho de fundo) para executar trabalhos em segundo plano, mas não podemos alterar os scripts de inicialização/níveis de inicialização no servidor. Isso significa que o daemon não deve permanecer disponível se o provedor reiniciar o servidor (já que o daemon seria iniciado por uma receita Capistrano que é executada apenas uma vez por implantação).

Atualmente, a melhor maneira de pensar para garantir que o daemon time_job esteja sempre em execução é adicionar um inicializador ao nosso aplicativo Rails que verifica se o daemon está em execução. Se não estiver em execução, o inicializador inicia o daemon; caso contrário, ele apenas deixa.

A questão, portanto, é como detectamos que o daemon touched_job está funcionando de dentro de um script? (Deveríamos ser capazes de iniciar um daemon com bastante facilidade, um pouco não sei como detectar se um já está ativo).

Alguém tem alguma ideia?

Atenciosamente, Bernie

Com base na resposta abaixo, foi isso que eu criei. Basta colocá -lo em Config/Initializadores e você está pronto:

#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
Foi útil?

Solução

Verifique a existência do arquivo pid daemons (File.exist? ...). Se estiver lá, assuma que está funcionando mais, inicie -o.

Outras dicas

Algumas idéias de limpeza: o "começo" não é necessário. Você deve resgatar "nenhum processo" para não demitir novos processos quando algo mais der errado. Resgate "nenhum arquivo ou diretório" também para simplificar a condição.

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?

Lembre -se de que este código não funcionará se você iniciar mais de um trabalhador. E confira o argumento "-m" do script/touched_job, que gera um processo de monitor junto com o (s) daemon (s).

Obrigado pela solução fornecida na pergunta (e pela resposta que a inspirou :-)), funciona para mim, mesmo com vários trabalhadores (Rails 3.2.9, Ruby 1.9.3p327).

Isso me preocupa que eu possa esquecer de reiniciar o atraso_job depois de fazer algumas alterações no Lib, por exemplo, fazendo -me depurar por horas antes de perceber isso.

Eu adicionei o seguinte ao meu script/rails Arquivo para permitir que o código fornecido na pergunta seja executado toda vez que iniciamos o Rails, mas nem toda vez que um trabalhador inicia:

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."

Uma pequena desvantagem que estou enfrentando com isso é que também é chamado rails generate por exemplo. Não gastei muito tempo procurando uma solução para isso, mas as sugestões são bem-vindas :-)

Observe que, se você estiver usando unicórnio, convém adicionar o mesmo código a config/unicorn.rb antes de o before_fork ligar.

- Editado:Depois de brincar um pouco mais com as soluções acima, acabei fazendo o seguinte:

Eu criei um arquivo script/start_delayed_job.rb com o conteúdo:

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."

Agora posso exigir esse arquivo em qualquer lugar que eu queira, incluindo 'script/trilhos' e 'config/unicorn.rb' fazendo:

# 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}"

não é ótimo, mas funciona

Isenção de responsabilidade: eu digo não ótimo porque isso causa uma reinicialização periódica, o que para muitos não será desejável. E simplesmente tentar iniciar pode causar problemas, porque a implementação do DJ pode bloquear a fila se as instâncias duplicadas forem criadas.

Você pode agendar cron tarefas que são executadas periodicamente para iniciar o (s) emprego (s) em questão. Como o DJ trata os comandos iniciantes como ninguém quando o trabalho já está em execução, ele funciona. Essa abordagem também cuida do caso em que o DJ morre por algum motivo que não seja um reinicialização do host.

# 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'

Se você está usando uma jóia como whenever Isso é bem direto.

every 1.hour do
  script "delayed_job --queue=default -i=1 restart"
  script "delayed_job --queue=lowpri -i=2 restart"
end
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top