2010-12-15 123 views
1

Je fais une application appelée club de lecture. Beaucoup de livres avec des votes seront dans le système. Chaque mois, le premier du mois, j'ai besoin du système pour promouvoir automatiquement le livre avec le plus grand nombre de votes pour être le «livre du mois». La logique de promouvoir un livre et d'assurer qu'un seul livre du mois existe a déjà été mis en œuvre.Rails application doit effectuer une tâche une fois par mois

book.promote! 

Belle, hein?

Je me ont un test hurr

Given the following books exist: 
    | title    | author   | year_published | votes | created_at  | 
    | Lord of the Flies | William Golding | 1954   | 18 | January 12, 2010 | 
    | The Virgin Suicides | Jeffrey Eugenides | 1993   | 12 | February 15, 2010 | 
    | Island    | Richard Laymon | 1991   | 6  | November 22, 2009 | 
And the book "Lord of the Flies" is the current book of the month 
And the date is "February 24, 2010" 
Then the book "Lord of the Flies" should be the current book of the month 
When the date is "March 1, 2010" 
And I am on the home page 
Then I should see "This Month's Book of the Month Club Book" 
And I should see "The Virgin Suicides" 
And the book "The Virgin Suicides" should be the current book of the month 
And the book "Lord of the Flies" should not be the current book of the month 
And the book "Island" should not be the current book of the month 

Et je suis en train d'obtenir ce passage. Donc la question est, comment puis-je mettre en œuvre une mise à jour automatique, une fois par mois, qui peut être testée par ce scénario?

Cron est un peu trop mouillé à mon goût. Je voudrais une solution plus portable.

delayed_job/Resque semble un peu trop lourd pour la situation. De plus, je ne sais pas trop comment les faire exécuter une fois par mois. À la recherche d'une solution simple, mais robuste et TESTABLE.

Bravo, comme toujours!

+1

Si vous pouvez expliquer pourquoi 'cron' est trop bâclé pour vous, je peux vous suggérer de meilleures alternatives. – Swanand

+0

Pour utiliser cron, je dois commencer à faire des suppositions dans ma suite de tests. Je peux faire la tâche de rake que le job cron appelle et tester, mais il me reste encore à faire l'hypothèse que les jobs cron seront mis en place dans mon environnement. Peut-être que je suis un peu pédant à ce moment-là, mais cela ne me semble pas juste de ne pas pouvoir couvrir un aspect aussi crucial du système. – drmanitoba

Répondre

1

Une belle façon de gérer les tâches périodiques est avec chaque fois: https://github.com/javan/whenever

Je ne l'utilise OS Cron, mais toutes les config vit dans votre application rails, il est donc plus agréable de travailler avec. Cependant, bien que ce soit assez approprié pour les tâches de type maintenance, par exemple si, pour une raison ou une autre, quelque chose ne fonctionne pas exactement en haut de l'heure ou est ignoré pour une raison quelconque, le relâchement sera pris en compte temps, dans votre cas où la chose périodique fait partie de la tâche, c'est un appel plus difficile. Peut-être que l'application peut se demander "toujours" si elle est la première du mois mais quand le classement est chargé, et si c'est le cas, elle fera le compte, en utilisant uniquement les votes dans la plage de dates appropriée?

Et pour tester le comportement en fonction du temps, la caisse à Timecop: https://github.com/jtrupiano/timecop

+0

Je pensais faire la méthode "always ask itself" avec un before_filter sur ApplicationController, mais j'ai commencé à me demander si cela allait devenir un gaspillage inutile de ressources à chaque requête. – drmanitoba

0

Comme John a commencé à dire Cron/Whenever est la voie à suivre ici. Les autres démons d'arrière-plan nécessitent un processus distinct qui sera inactif la plupart du temps. Vous ne devriez pas avoir de problèmes de portabilité avec cron, sauf si vous vous inquiétez de courir sur Windows.

0

Nous parlons de deux choses différentes ici:

  1. Un travail qui exécute et exécute la tâche pour le système: Ce serait par rake, il est assez fiable et bien testé.
  2. Un planificateur qui exécute cette tâche selon une planification que vous spécifiez. Il semble que vous cherchiez des alternatives à cron. Vous pouvez essayer launchd pour cela.
1

J'utilise delayed_job pour ce type d'exigences.

class Book 
    def promote 
    # code for the promote method.. 

    ensure 
    # re-run the task in another 30 days. 
    promote 
    end 
    # Date.today.nextmonth.beginning_of_month will be evaluated 
    #when promote is called 
    handle_asynchronously :promote, :run_at => Proc.new { 
    Date.today.next_month.beginning_of_month 
    } 

end 
+0

Je ne connais pas trop DJ. Comment ajouter cette tâche à la file une fois que j'ai cette configuration? – drmanitoba

+0

Appelez la méthode 'promote' une fois sur l'objet livre, cela ajoutera un travail à la file d'attente. A partir de ce moment, la méthode sera appelée tous les mois. –

0

le travail de retardé est vraiment un bon choix. Vous testez actuellement avec un petit nombre de livres, donc le calcul promote est fait assez rapidement. Lorsque votre application est mise à l'échelle, vous souhaiterez exécuter ce calcul dans un processus de travail distinct afin de réduire l'impact sur l'expérience utilisateur.

delayed_job fera d'une pierre deux coups: fournir un mécanisme de planification et décharger le calcul promote dans un processus de travail distinct.