web-dev-qa-db-fra.com

Un travail cron pour Rails: les meilleures pratiques?

Quelle est la meilleure façon d'exécuter des tâches planifiées dans un environnement Rails? Script/coureur? Râteau?

291
jes5199

J'utilise l'approche rake (telle que supportée par heroku )

Avec un fichier appelé lib/tasks/cron.rake ..

task :cron => :environment do
  puts "Pulling new requests..."
  EdiListener.process_new_messages
  puts "done."
end

Pour exécuter à partir de la ligne de commande, il s'agit simplement de "rake cron". Cette commande peut ensuite être placée sur le programmateur cron/tâche du système d'exploitation à votre guise.

Mise à jour C'est une question assez ancienne et la réponse! Quelques nouvelles informations:

  • le service heroku cron auquel j'ai fait référence a depuis été remplacé par Heroku Scheduler
  • pour les tâches fréquentes (en particulier lorsque vous souhaitez éviter le coût de démarrage de l'environnement Rails), mon approche préférée consiste à utiliser system cron pour appeler un script qui (a) lance une API Webhook sécurisée/privée pour appeler la tâche requise en arrière-plan ou (b) mettre directement une tâche en file d'attente sur le système de votre choix 
108
tardate

J'ai utilisé le très populaire Whenever sur des projets qui reposent beaucoup sur des tâches planifiées, et c'est génial. Il vous donne un joli DSL pour définir vos tâches planifiées au lieu d'avoir à traiter avec le format crontab. Du README:

Chaque fois que c'est un joyau de rubis qui fournit un syntaxe claire pour l'écriture et le déploiement emplois cron.

Exemple tiré du fichier README:

every 3.hours do
  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
252
Jim Garvin

En supposant que vos tâches ne prennent pas trop de temps, créez simplement un nouveau contrôleur avec une action pour chaque tâche. Implémentez la logique de la tâche en tant que code de contrôleur, puis configurez une tâche cron au niveau du système d'exploitation qui utilise wget pour appeler l'URL de ce contrôleur et l'action aux intervalles de temps appropriés. Les avantages de cette méthode sont vous:

  1. Ayez un accès complet à tous vos objets Rails, comme dans un contrôleur normal.
  2. Peut développer et tester comme vous le faites les actions normales. 
  3. Vous pouvez également appeler vos tâches à partir d’une simple page Web.
  4. Ne consommez plus de mémoire en activant des processus Ruby/Rails supplémentaires.
17
Freakent

Dans notre projet, nous avons d’abord utilisé à chaque fois une pierre précieuse, mais avons rencontré quelques problèmes.

Nous sommes ensuite passés à RUFUS SCHEDULER gem, qui s’est avéré très facile et fiable pour la planification des tâches dans Rails.

Nous l'avons utilisé pour l'envoi d'emails hebdomadaires et quotidiens, et même pour l'exécution de tâches de commission périodiques ou de n'importe quelle méthode.

Le code utilisé dans ceci est comme:

    require 'rufus-scheduler'

    scheduler = Rufus::Scheduler.new

    scheduler.in '10d' do
      # do something in 10 days
    end

    scheduler.at '2030/12/12 23:30:00' do
      # do something at a given point in time
    end

    scheduler.every '3h' do
      # do something every 3 hours
    end

    scheduler.cron '5 0 * * *' do
      # do something every day, five minutes after midnight
      # (see "man 5 crontab" in your terminal)
    end

Pour en savoir plus: https://github.com/jmettraux/rufus-scheduler

15
Pankhuri

Je suis un grand fan de resque / resque scheduler . Vous pouvez non seulement exécuter des tâches répétitives de type Cron, mais également des tâches à des moments spécifiques. L'inconvénient est qu'il nécessite un serveur Redis.

10
Tyler Morgan

Le problème avec when (et cron) est qu’il recharge l’environnement Rails chaque fois qu’il est exécuté, ce qui est un problème réel lorsque vos tâches sont fréquentes ou qu’il ya beaucoup de travail d’initialisation à effectuer. J'ai eu des problèmes de production à cause de cela et je dois vous prévenir.

Rufus scheduler le fait pour moi ( https://github.com/jmettraux/rufus-scheduler )

Quand j'ai de longues tâches à exécuter, je l'utilise avec delay_job ( https://github.com/collectiveidea/delayed_job )

J'espère que ça aide!

10
Abdo

C’est intéressant, personne n’a mentionné le Sidetiq . C’est un ajout intéressant si vous utilisez déjà Sidekiq.

Sidetiq fournit une API simple permettant de définir des travailleurs récurrents pour Sidekiq.

Job va ressembler à ceci:

class MyWorker
  include Sidekiq::Worker
  include Sidetiq::Schedulable

  recurrence { hourly.minute_of_hour(15, 45) }

  def perform
    # do stuff ...
  end
end
9
AlexParamonov

les tâches script/runner et rake conviennent parfaitement pour être exécutées en tant que tâches cron.

Voici une chose très importante à prendre en compte lors de l’exécution de tâches cron. Ils ne seront probablement pas appelés à partir du répertoire racine de votre application. Cela signifie que tous vos besoins en fichiers (par opposition aux bibliothèques) doivent être effectués avec le chemin explicite: par exemple. File.dirname (__ FILE__) + "/ other_file". Cela signifie également que vous devez savoir comment les appeler explicitement depuis un autre répertoire :-)

Vérifiez si votre code prend en charge l'exécution depuis un autre répertoire avec 

# 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

En outre, les tâches cron ne s'exécutent probablement pas comme vous le souhaitez, aussi ne dépendez pas du raccourci que vous avez mis dans. Mais ce n’est qu’une astuce cron classique ;-)

9
webmat

Les deux fonctionneront bien. J'utilise habituellement script/runner. 

Voici un exemple:

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

Vous pouvez également écrire un script pur-Ruby à cette fin si vous chargez les bons fichiers de configuration pour vous connecter à votre base de données.

Une chose à garder à l’esprit si la mémoire est précieuse est que le script/exécutant (ou une tâche de ratissage qui dépend de «l’environnement») charge tout l’environnement Rails. Si vous devez uniquement insérer des enregistrements dans la base de données, vous utiliserez de la mémoire que vous n’êtes pas obligée de faire. Si vous écrivez votre propre script, vous pouvez éviter cela. Je n'ai pas encore eu besoin de le faire, mais je réfléchis.

8
Luke Francl

Utilisez Craken (travaux cron centraux)

8
Thibaut Barrère

J'utilise backgroundrb.

http://backgroundrb.rubyforge.org/

Je l'utilise pour exécuter des tâches planifiées ainsi que des tâches qui prennent trop de temps pour la relation client/serveur normale.

5
salt.racer

Utiliser quelque chose Sidekiq ou Resque est une solution bien plus robuste. Ils prennent tous les deux en charge les nouvelles tentatives d’emploi, l’exclusivité avec un verrou REDIS, la surveillance et la planification.

Gardez à l'esprit que Resque est un projet mort (pas activement maintenu), donc Sidekiq est une meilleure alternative. Il est également plus performant: Sidekiq exécute plusieurs travailleurs sur un seul processus multithread, tandis que Resque exécute chaque travailleur dans un processus séparé.

3
jaysqrd

J'ai récemment créé des emplois cron pour les projets sur lesquels j'ai travaillé.

J'ai trouvé que la gemme Clockwork était très utile.

require 'clockwork'

module Clockwork
  every(10.seconds, 'frequent.job')
end

Vous pouvez même planifier votre travail en arrière-plan à l’aide de cette gem .. .. Pour obtenir de la documentation et une aide supplémentaire, consultez https://github.com/Rykian/clockwork

3
Vipul Lawande

Voici comment j'ai configuré mes tâches cron. J'ai un pour faire des sauvegardes quotidiennes de la base de données SQL (en utilisant rake) et un autre pour expirer le cache une fois par mois. Toute sortie est enregistrée dans un fichier log/cron_log. Ma crontab ressemble à ceci:

crontab -l # command to print all cron tasks
crontab -e # command to edit/add cron tasks

# Contents of crontab
0 1 * * * cd /home/lenart/izziv. whiskas.si/current; /bin/sh cron_tasks >> log/cron_log 2>&1
0 0 1 * * 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

La première tâche périodique effectue des sauvegardes quotidiennes de la base de données. Le contenu de cron_tasks est le suivant:

/usr/local/bin/rake db:backup Rails_ENV=production; date; echo "END OF OUTPUT ----";

La deuxième tâche a été configurée plus tard et utilise script/runner pour faire expirer le cache une fois par mois (lib/mensuel_cron.rb):

#!/usr/local/bin/Ruby
# Expire challenge cache
Challenge.force_expire_cache
puts "Expired cache for Challenges (Challenge.force_expire_cache) #{Time.now}"

Je suppose que je pourrais sauvegarder la base de données d’une autre manière, mais jusqu’à présent, cela fonctionne pour moi :)

Les chemins pour ratisser et Ruby peuvent varier sur différents serveurs. Vous pouvez voir où ils se trouvent en utilisant:

whereis Ruby # -> Ruby: /usr/local/bin/Ruby
whereis rake # -> rake: /usr/local/bin/rake
3
Lenart

Une fois, j'ai dû prendre la même décision et je suis vraiment heureuse de cette décision aujourd'hui. Utilisez resque scheduler , car non seulement un redis distinct enlèvera la charge de votre base de données, vous aurez également accès à de nombreux plugins, comme resque-web, qui fournit une excellente interface utilisateur. Au fur et à mesure que votre système évoluera, vous aurez de plus en plus de tâches à planifier pour pouvoir les contrôler à partir d'un seul endroit. 

2
Caner Çakmak

vous pouvez utiliser resque et resque-shheduler gem pour créer des crons, c’est très facile à faire.

https://github.com/resque/resque

https://github.com/resque/resque-scheduler

2
Israel Barba

J'ai utilisé clockwork gem et ça marche plutôt bien pour moi. Il existe également une gemme clockworkd qui permet à un script de s'exécuter en tant que démon.

1
nnattawat

La meilleure façon de le faire est probablement d’utiliser rake pour écrire les tâches dont vous avez besoin et de simplement l’exécuter via la ligne de commande.

Vous pouvez voir une vidéo très utile vidéo sur railscasts

Jetez également un coup d'œil à ces autres ressources:

1
Adrià Cidre

Je ne suis pas vraiment sûr, je suppose que cela dépend de la tâche: combien de fois exécuter, combien de complications et combien de communication directe avec le projet Rails est nécessaire, etc. Je suppose que s'il y avait juste "One Best Way" pour faire quelque chose, il n’y aurait pas autant de façons différentes de le faire.

Lors de mon dernier travail dans un projet Rails, nous devions créer un courrier d'invitations par lot (invitations à une enquête, pas de spam) qui devrait envoyer les courriers planifiés à chaque fois que le serveur en avait le temps. Je pense que nous allions utiliser daemon tools pour exécuter les tâches de rake que j'avais créées. 

Malheureusement, notre société a eu des problèmes d’argent et a été "achetée" par son principal rival. Le projet n’a donc jamais été achevé. Je ne sais pas ce que nous aurions éventuellement utilisé.

0

I Utilisez script pour exécuter cron, c’est le meilleur moyen d’exécuter un cron . Voici quelques exemples pour cron,

Ouvrir CronTab -> Sudo crontab -e

Et coller les lignes ci-dessous:

00 00 * * * wget https: // your_host/some_API_end_point

Voici un format de cron, vous aidera

::CRON FORMAT::

 cron format table

Examples Of crontab Entries
15 6 2 1 * /home/melissa/backup.sh
Run the Shell script /home/melissa/backup.sh on January 2 at 6:15 A.M.

15 06 02 Jan * /home/melissa/backup.sh
Same as the above entry. Zeroes can be added at the beginning of a number for legibility, without changing their value.

0 9-18 * * * /home/carl/hourly-archive.sh
Run /home/carl/hourly-archive.sh every hour, on the hour, from 9 A.M. through 6 P.M., every day.

0 9,18 * * Mon /home/wendy/script.sh
Run /home/wendy/script.sh every Monday, at 9 A.M. and 6 P.M.

30 22 * * Mon,Tue,Wed,Thu,Fri /usr/local/bin/backup
Run /usr/local/bin/backup at 10:30 P.M., every weekday. 

J'espère que ceci vous aidera :)

0
Ami