Qual é a melhor maneira de executar tarefas agendadas em um ambiente Rails? Script / corredor? Ancinho? Eu gostaria de executar a tarefa a cada poucos minutos.
Em muitos casos, os trabalhos cron são um mau cheiro. Melhor agendador de gravação através do sidekiq / resque (ou outro trabalhador em segundo plano) ou escreva um daemon (menos funcional e monitorável). Os empregos temporários têm pelo menos algumas coisas ruins: 1) bloquear uma instância é uma dor; 2) o monitoramento não pode ser feito facilmente; 3) o tratamento de exceções deve ser escrito manualmente novamente; 4) não é fácil reiniciar; 5) todas as questões acima resolvidas facilmente pelos trabalhadores em segundo plano.
Dmitry Polushkin
Respostas:
110
Estou usando a abordagem rake (conforme suportado por heroku )
Com um arquivo chamado lib / tasks / cron.rake ..
task :cron =>:environment do
puts "Pulling new requests..."EdiListener.process_new_messages
puts "done."end
Para executar a partir da linha de comando, isso é apenas "rake cron". Esse comando pode ser colocado no cron / agendador de tarefas do sistema operacional, conforme desejado.
Atualizar esta é uma pergunta e resposta bastante antigas! Algumas novas informações:
o serviço heroku cron que referenciei foi substituído pelo Heroku Scheduler
para tarefas frequentes (especialmente onde você deseja evitar o custo de inicialização do ambiente Rails), minha abordagem preferida é usar o cron do sistema para chamar um script que (a) cutuca uma API webhook segura / privada para invocar a tarefa necessária em segundo plano ou (b) enfileirar diretamente uma tarefa no seu sistema de filas de escolha
Qual deve ser a entrada cron neste caso, para que o sistema operacional conheça o caminho correto para a tarefa rake?
Jrdioko
13
NB: hoje em dia estou usando sempre (consulte a resposta de Jim Garvin), mas uma entrada cron bruta para executar tarefas de rake seria algo como: 30 4 * * * / bin / bash -l -c 'cd / opt / railsapp && RAILS_ENV = rake de produção cron --silent '
atrasado 12/07
1
Como você chama isso no console? Eu fiz load "#{Rails.root}/lib/tasks/cron.rake"e rake cron, mas obtive NameError: variável local indefinida ou método `cron 'para main: Object
B Seven
3
O problema com essa abordagem é a :environmentdependência. Temos um aplicativo Rails muito pesado que demora muito para iniciar, nosso Rake é chamado a cada minuto e consome mais recursos iniciando o ambiente Rails que executa a tarefa . Eu adoraria ter um ambiente Rails já iniciado para ser chamado através do cron, deve haver algo entre a abordagem do controlador e a do ambiente rake .
fguillen
Qual é a duração desta tarefa? Estou usando uma condição if. Quero saber com que regularidade isso é executado. Não consigo encontrar nenhuma informação sobre isso no site heroku.
Shubham Chaudhary
254
Eu usei o extremamente popular Whenever em projetos que dependem muito de tarefas agendadas, e é ótimo. Ele fornece um bom DSL para definir suas tarefas agendadas em vez de precisar lidar com o formato crontab. No README:
Sempre que é uma gema Ruby, fornece uma sintaxe clara para escrever e implantar tarefas cron.
Exemplo do README:
every 3.hoursdo
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"end
every 1.day,:at =>'4:30 am'do
runner "MyModel.task_to_run_at_four_thirty_in_the_morning"end
Se for executado a cada minuto, o ambiente será reiniciado todas as vezes, o que pode ser caro. Parece que o github.com/ssoroka/scheduler_daemon evita isso.
Lulalala #
3
+1 para manter a configuração cron com seu sistema de controle de versão
brittohalloran
3
Eu acho que essa é a melhor solução. Se você estiver usando trilhos, acho melhor escrever tudo em trilhos. Com essa abordagem, você também pode esquecer a tarefa cron ao alterar servidores, ela se move com o aplicativo.
Adrian Matteo
Existe um ótimo Railscast sobre Sempre que é realmente útil (também existe uma versão gratuita mais antiga).
Aceofbassgreg 11/04
@ Tony, Sempre que é basicamente uma linguagem específica de domínio para escrever trabalhos cron. Ele é compilado na sintaxe cron regular no servidor rails e o cron é o que executa as tarefas que você especificar (geralmente através do corredor rails).
Greg
19
Em nosso projeto, usamos pela primeira vez sempre que gem, mas enfrentamos alguns problemas.
Em seguida, mudamos para a gema RUFUS SCHEDULER , que acabou sendo muito fácil e confiável para agendar tarefas no Rails.
Nós o usamos para enviar e-mails semanais e diários e até para executar algumas tarefas periódicas de rake ou qualquer outro método.
O código usado é o seguinte:
require'rufus-scheduler'
scheduler =Rufus::Scheduler.new
scheduler.in'10d'do# do something in 10 daysend
scheduler.at '2030/12/12 23:30:00'do# do something at a given point in timeend
scheduler.every '3h'do# do something every 3 hoursend
scheduler.cron '5 0 * * *'do# do something every day, five minutes after midnight# (see "man 5 crontab" in your terminal)end
Adequado para o rufus, como eu o usei em projetos simples de rubi ou em aplicativos rails completos.
Paulo Fidalgo
8
Você poderia ser um pouco mais específico sobre os problemas com o Whenever?
Duke
a resposta mais ótima de todos os tempos
Darlan Dieterich
17
Supondo que suas tarefas não demorem muito para serem concluídas, basta criar um novo controlador com uma ação para cada tarefa. Implemente a lógica da tarefa como código do controlador e, em seguida, configure um cronjob no nível do sistema operacional que use o wget para chamar a URL desse controlador e a ação nos intervalos de tempo apropriados. As vantagens deste método são você:
Tenha acesso total a todos os seus objetos Rails, como em um controlador normal.
Pode desenvolver e testar exatamente como você faz ações normais.
Também pode invocar suas tarefas adhoc a partir de uma simples página da web.
Não consuma mais memória acionando processos adicionais de ruby / rails.
Como impedir que outras pessoas acessem esta tarefa? Se a tarefa que leva a CPU e a chama com frequência causa problemas.
22410 sarunw
44
Eu sei que isso foi há um tempo atrás, mas essa definitivamente não é mais a melhor maneira de fazer trabalhos cron. Por que acessar a interface da Web, violando o que a interface realmente representa, quando existem muitas outras maneiras de acessar o ambiente Rails?
Matchu
6
A qualificação "assumindo que suas tarefas não demoram muito para ser concluída" parece uma ENORME. Não seria melhor usar uma abordagem geralmente mais útil, e não apenas nos casos em que as tarefas são muito rápidas? Dessa forma, você não está constantemente reavaliando se essa ou aquela tarefa precisa ser reescrita usando uma abordagem diferente.
Iconoclasta
77
Esta pergunta antiga é o principal resultado do google para "rails cron". Esta resposta está longe de ser a melhor abordagem. Por favor, veja as outras respostas para sugestões mais sensatas.
21711 Jim Carvin
2
Não é o melhor caminho. Você tem muitas outras maneiras de acessar o ambiente do Rails por meio de uma tarefa cron sem chamar um serviço REST. Abordagem Rake é certamente melhor
Equipamento para engraxar os
10
As tarefas de script / runner e rake são perfeitas para serem executadas como tarefas cron.
Aqui está uma coisa muito importante que você deve lembrar ao executar tarefas cron. Eles provavelmente não serão chamados no diretório raiz do seu aplicativo. Isso significa que todos os seus requisitos para arquivos (ao contrário de bibliotecas) devem ser feitos com o caminho explícito: por exemplo, File.dirname (__ FILE__) + "/ other_file". Isso também significa que você precisa saber como chamá-los explicitamente de outro diretório :-)
Verifique se o seu código suporta a execução de outro diretório com
# from ~/path/to/ruby /path/to/app/script/runner -e development "MyClass.class_method"/path/to/ruby /path/to/rake -f /path/to/app/Rakefile rake:task RAILS_ENV=development
Além disso, os trabalhos cron provavelmente não são executados como você, portanto, não dependa de nenhum atalho inserido no .bashrc. Mas isso é apenas uma dica cron padrão ;-)
Você pode executar o trabalho como qualquer usuário (basta definir a entrada crontab para o usuário desejado), mas você está certo de que o perfil e os scripts de logon não serão executados e você não iniciará no diretório inicial. Por isso, é comum para iniciar o comando com um "cd", como mostrado no comentário de @ luke-Franci
Tom Wilson
10
O problema de quando (e cron) é que ele recarrega o ambiente de trilhos toda vez que é executado, o que é um problema real quando suas tarefas são frequentes ou têm muito trabalho de inicialização a ser feito. Eu tive problemas na produção por causa disso e devo avisá-lo.
Sou um grande fã do resque / resque scheduler . Você não pode apenas executar tarefas repetidas do tipo cron, mas também tarefas em horários específicos. A desvantagem é que ele requer um servidor Redis.
Ambos irão funcionar bem. Eu costumo usar script / runner.
Aqui está um exemplo:
0 6 * * * cd /var/www/apps/your_app/current; ./script/runner --environment production 'EmailSubscription.send_email_subscriptions' >> /var/www/apps/your_app/shared/log/send_email_subscriptions.log 2>&1
Você também pode escrever um script Ruby puro para fazer isso se carregar os arquivos de configuração corretos para se conectar ao seu banco de dados.
Uma coisa a ter em mente se a memória é preciosa é que o script / runner (ou uma tarefa Rake que depende do 'ambiente') carregará todo o ambiente do Rails. Se você apenas precisar inserir alguns registros no banco de dados, isso utilizará a memória que você realmente não precisa. Se você escrever seu próprio script, poderá evitar isso. Ainda não precisei fazer isso, mas estou considerando.
Aqui está como eu configurei minhas tarefas cron. Eu tenho um para fazer backups diários do banco de dados SQL (usando rake) e outro para expirar o cache uma vez por mês. Qualquer saída é registrada em um arquivo log / cron_log. Meu crontab fica assim:
crontab -l # command to print all cron tasks
crontab -e # command to edit/add cron tasks# Contents of crontab01*** cd /home/lenart/izziv. whiskas.si/current;/bin/sh cron_tasks >> log/cron_log 2>&1001** cd /home/lenart/izziv.whiskas.si/current;/usr/bin/env /usr/local/bin/ruby script/runner -e production lib/monthly_cron.rb >> log/cron_log 2>&1
A primeira tarefa do cron faz backups diários do banco de dados. O conteúdo de cron_tasks é o seguinte:
/usr/local/bin/rake db:backup RAILS_ENV=production; date; echo "END OF OUTPUT ----";
A segunda tarefa foi configurada posteriormente e usa script / runner para expirar o cache uma vez por mês (lib / Monthly_cron.rb):
Usar algo Sidekiq ou Resque é uma solução muito mais robusta. Ambos suportam a repetição de trabalhos, exclusividade com um bloqueio, monitoramento e programação REDIS.
Lembre-se de que o Resque é um projeto morto (não é mantido ativamente), portanto o Sidekiq é uma alternativa muito melhor. Ele também tem mais desempenho: o Sidekiq executa vários trabalhadores em um único processo multithread enquanto o Resque executa cada trabalhador em um processo separado.
Essa é uma resposta correta. Muitos podem esquecer os bons recursos que o sidekiq ou o resque estão fornecendo, como interface da web para monitorar o que está acontecendo: número de trabalhos em execução, com falha ou agendados, reiniciá-los facilmente, bloquear para trabalhadores únicos, limitar e limitar etc.
Dmitry Polushkin
3
Recentemente, criei alguns trabalhos cron para os projetos nos quais tenho trabalhado.
Você pode até agendar seu trabalho em segundo plano usando esta gema. Para documentação e ajuda adicional, consulte https://github.com/Rykian/clockwork
Uma vez eu tive que tomar a mesma decisão e estou muito feliz com essa decisão hoje. Use o resque scheduler porque não apenas um redis separado removerá a carga do seu banco de dados, você também terá acesso a muitos plugins como o resque-web, que fornece uma ótima interface de usuário. À medida que o seu sistema se desenvolve, você terá mais e mais tarefas para agendar e poderá controlá-las a partir de um único local.
Não tenho muita certeza, acho que depende da tarefa: quantas vezes executar, quão complicada e quanta comunicação direta com o projeto rails é necessária etc. Acho que se houvesse apenas "One Best Way" para fazer algo , não haveria tantas maneiras diferentes de fazer isso.
No meu último trabalho em um projeto do Rails, precisávamos fazer uma correspondência em lote (convites para pesquisas, não spam), que deveria enviar as mensagens planejadas sempre que o servidor tivesse tempo. Acho que íamos usar as ferramentas daemon para executar as tarefas de rake que eu havia criado.
Infelizmente, nossa empresa teve alguns problemas financeiros e foi "comprada" pelo principal rival para que o projeto nunca fosse concluído, então não sei o que eventualmente teríamos usado.
ExamplesOf crontab Entries15621*/home/melissa/backup.sh
Run the shell script /home/melissa/backup.sh on January2 at 6:15 A.M.150602Jan*/home/melissa/backup.sh
Sameas the above entry.Zeroes can be added at the beginning of a number for legibility, without changing their value.09-18***/home/carl/hourly-archive.sh
Run/home/carl/hourly-archive.sh every hour, on the hour,from9 A.M. through 6 P.M., every day.09,18**Mon/home/wendy/script.sh
Run/home/wendy/script.sh every Monday, at 9 A.M.and6 P.M.3022**Mon,Tue,Wed,Thu,Fri/usr/local/bin/backup
Run/usr/local/bin/backup at 10:30 P.M., every weekday.
Respostas:
Estou usando a abordagem rake (conforme suportado por heroku )
Com um arquivo chamado lib / tasks / cron.rake ..
Para executar a partir da linha de comando, isso é apenas "rake cron". Esse comando pode ser colocado no cron / agendador de tarefas do sistema operacional, conforme desejado.
Atualizar esta é uma pergunta e resposta bastante antigas! Algumas novas informações:
fonte
load "#{Rails.root}/lib/tasks/cron.rake"
erake cron
, mas obtive NameError: variável local indefinida ou método `cron 'para main: Object:environment
dependência. Temos um aplicativo Rails muito pesado que demora muito para iniciar, nosso Rake é chamado a cada minuto e consome mais recursos iniciando o ambiente Rails que executa a tarefa . Eu adoraria ter um ambiente Rails já iniciado para ser chamado através do cron, deve haver algo entre a abordagem do controlador e a do ambiente rake .Eu usei o extremamente popular Whenever em projetos que dependem muito de tarefas agendadas, e é ótimo. Ele fornece um bom DSL para definir suas tarefas agendadas em vez de precisar lidar com o formato crontab. No README:
Exemplo do README:
fonte
Em nosso projeto, usamos pela primeira vez sempre que gem, mas enfrentamos alguns problemas.
Em seguida, mudamos para a gema RUFUS SCHEDULER , que acabou sendo muito fácil e confiável para agendar tarefas no Rails.
Nós o usamos para enviar e-mails semanais e diários e até para executar algumas tarefas periódicas de rake ou qualquer outro método.
O código usado é o seguinte:
Para saber mais: https://github.com/jmettraux/rufus-scheduler
fonte
Supondo que suas tarefas não demorem muito para serem concluídas, basta criar um novo controlador com uma ação para cada tarefa. Implemente a lógica da tarefa como código do controlador e, em seguida, configure um cronjob no nível do sistema operacional que use o wget para chamar a URL desse controlador e a ação nos intervalos de tempo apropriados. As vantagens deste método são você:
fonte
As tarefas de script / runner e rake são perfeitas para serem executadas como tarefas cron.
Aqui está uma coisa muito importante que você deve lembrar ao executar tarefas cron. Eles provavelmente não serão chamados no diretório raiz do seu aplicativo. Isso significa que todos os seus requisitos para arquivos (ao contrário de bibliotecas) devem ser feitos com o caminho explícito: por exemplo, File.dirname (__ FILE__) + "/ other_file". Isso também significa que você precisa saber como chamá-los explicitamente de outro diretório :-)
Verifique se o seu código suporta a execução de outro diretório com
Além disso, os trabalhos cron provavelmente não são executados como você, portanto, não dependa de nenhum atalho inserido no .bashrc. Mas isso é apenas uma dica cron padrão ;-)
fonte
O problema de quando (e cron) é que ele recarrega o ambiente de trilhos toda vez que é executado, o que é um problema real quando suas tarefas são frequentes ou têm muito trabalho de inicialização a ser feito. Eu tive problemas na produção por causa disso e devo avisá-lo.
O agendador Rufus faz isso por mim ( https://github.com/jmettraux/rufus-scheduler )
Quando tenho trabalhos longos para executar, uso-o com delayed_job ( https://github.com/collectiveidea/delayed_job )
Eu espero que isso ajude!
fonte
Sou um grande fã do resque / resque scheduler . Você não pode apenas executar tarefas repetidas do tipo cron, mas também tarefas em horários específicos. A desvantagem é que ele requer um servidor Redis.
fonte
Isso é interessante, ninguém mencionou o Sidetiq . É uma boa adição se você já estiver usando o Sidekiq.
Jó terá a seguinte aparência:
fonte
Ambos irão funcionar bem. Eu costumo usar script / runner.
Aqui está um exemplo:
0 6 * * * cd /var/www/apps/your_app/current; ./script/runner --environment production 'EmailSubscription.send_email_subscriptions' >> /var/www/apps/your_app/shared/log/send_email_subscriptions.log 2>&1
Você também pode escrever um script Ruby puro para fazer isso se carregar os arquivos de configuração corretos para se conectar ao seu banco de dados.
Uma coisa a ter em mente se a memória é preciosa é que o script / runner (ou uma tarefa Rake que depende do 'ambiente') carregará todo o ambiente do Rails. Se você apenas precisar inserir alguns registros no banco de dados, isso utilizará a memória que você realmente não precisa. Se você escrever seu próprio script, poderá evitar isso. Ainda não precisei fazer isso, mas estou considerando.
fonte
Use Craken (tarefas cron centralizadas em rake)
fonte
Eu uso backgroundrb.
http://backgroundrb.rubyforge.org/
Eu o uso para executar tarefas agendadas, bem como tarefas que demoram muito para o relacionamento normal de cliente / servidor.
fonte
Aqui está como eu configurei minhas tarefas cron. Eu tenho um para fazer backups diários do banco de dados SQL (usando rake) e outro para expirar o cache uma vez por mês. Qualquer saída é registrada em um arquivo log / cron_log. Meu crontab fica assim:
A primeira tarefa do cron faz backups diários do banco de dados. O conteúdo de cron_tasks é o seguinte:
A segunda tarefa foi configurada posteriormente e usa script / runner para expirar o cache uma vez por mês (lib / Monthly_cron.rb):
Eu acho que eu poderia fazer backup do banco de dados de outra maneira, mas até agora funciona para mim :)
Os caminhos para o rake e o ruby podem variar em diferentes servidores. Você pode ver onde eles estão usando:
fonte
Usar algo Sidekiq ou Resque é uma solução muito mais robusta. Ambos suportam a repetição de trabalhos, exclusividade com um bloqueio, monitoramento e programação REDIS.
Lembre-se de que o Resque é um projeto morto (não é mantido ativamente), portanto o Sidekiq é uma alternativa muito melhor. Ele também tem mais desempenho: o Sidekiq executa vários trabalhadores em um único processo multithread enquanto o Resque executa cada trabalhador em um processo separado.
fonte
Recentemente, criei alguns trabalhos cron para os projetos nos quais tenho trabalhado.
Achei que a gema Clockwork era muito útil.
Você pode até agendar seu trabalho em segundo plano usando esta gema. Para documentação e ajuda adicional, consulte https://github.com/Rykian/clockwork
fonte
você pode usar
resque
eresque-schedular
gem para criar cron, isso é muito fácil de fazer.https://github.com/resque/resque
https://github.com/resque/resque-scheduler
fonte
Uma vez eu tive que tomar a mesma decisão e estou muito feliz com essa decisão hoje. Use o resque scheduler porque não apenas um redis separado removerá a carga do seu banco de dados, você também terá acesso a muitos plugins como o resque-web, que fornece uma ótima interface de usuário. À medida que o seu sistema se desenvolve, você terá mais e mais tarefas para agendar e poderá controlá-las a partir de um único local.
fonte
Provavelmente, a melhor maneira de fazer isso é usar o rake para escrever as tarefas que você precisa e apenas executá-lo via linha de comando.
Você pode ver um vídeo muito útil em railscasts
Veja também outros recursos:
fonte
Eu usei um relógio e funciona muito bem para mim. Também existe uma
clockworkd
gema que permite que um script seja executado como um daemon.fonte
Não tenho muita certeza, acho que depende da tarefa: quantas vezes executar, quão complicada e quanta comunicação direta com o projeto rails é necessária etc. Acho que se houvesse apenas "One Best Way" para fazer algo , não haveria tantas maneiras diferentes de fazer isso.
No meu último trabalho em um projeto do Rails, precisávamos fazer uma correspondência em lote (convites para pesquisas, não spam), que deveria enviar as mensagens planejadas sempre que o servidor tivesse tempo. Acho que íamos usar as ferramentas daemon para executar as tarefas de rake que eu havia criado.
Infelizmente, nossa empresa teve alguns problemas financeiros e foi "comprada" pelo principal rival para que o projeto nunca fosse concluído, então não sei o que eventualmente teríamos usado.
fonte
Eu uso o script para executar o cron, que é a melhor maneira de executar um cron. Aqui está um exemplo para cron,
Abra o CronTab -> sudo crontab -e
E Cole as linhas abaixo:
00 00 * * * wget https: // your_host / some_API_end_point
Aqui está um formato cron, irá ajudá-lo
Espero que isso ajude você :)
fonte