33 votes

Meilleure pratique pour une application Rails pour exécuter une longue tâche en arrière-plan ?

J'ai une application Rails qui, malheureusement, après une requête à un contrôleur, doit faire des calculs qui prennent un certain temps. Quelles sont les meilleures pratiques dans Rails pour fournir un retour d'information ou une progression sur une tâche ou une requête de longue durée ? Ces méthodes de contrôleur durent généralement plus de 60 secondes.

Je ne suis pas concerné par le côté client... J'avais prévu d'avoir une requête Ajax toutes les secondes environ et d'afficher un indicateur de progression. Je ne suis pas sûr de la meilleure pratique de Rails, dois-je créer un contrôleur supplémentaire ? Y a-t-il quelque chose d'ingénieux que je puisse faire ? Je veux que les réponses se concentrent sur le côté serveur en utilisant uniquement Rails.

Merci d'avance pour votre aide.

Edit :

Si cela a de l'importance, les demandes http sont pour les PDFs. Je fais ensuite générer ces PDF par Rails en conjonction avec Ruport. Le problème est que ces PDF sont très volumineux et contiennent beaucoup de données. Est-il toujours utile d'utiliser une tâche d'arrière-plan ? Supposons qu'un PDF moyen prenne entre une et deux minutes, cela rendra-t-il mon application Rails insensible à toute autre requête du serveur pendant ce temps ?

Edit 2 :

Ok, après une enquête plus approfondie, il semble que mon application Rails ne réponde pas aux autres requêtes HTTP après qu'une demande de PDF volumineux ait été reçue. Donc, je suppose que la question devient maintenant : Quel est le meilleur mécanisme de filtrage/arrière-plan à utiliser ? Il doit être stable et entretenu. Je suis très surpris que Rails n'ait pas quelque chose comme ça intégré.

Edit 3 :

J'ai lu cette page : http://wiki.rubyonrails.org/rails/pages/HowToRunBackgroundJobsInRails . J'aimerais lire des articles sur les diverses expériences vécues avec ces outils.

Edit 4 :

J'utilise Passenger Phusion "modrails", si cela a de l'importance.

Edit 5 :

J'utilise Windows Vista 64 bits sur ma machine de développement, mais ma machine de production est Ubuntu 8.04 LTS. Devrais-je envisager de passer à Linux pour ma machine de développement ? Les solutions présentées fonctionneront-elles sur les deux ?

24voto

pantulis Points 1212

En Plugin Workling vous permettent de planifier des tâches d'arrière-plan dans une file d'attente (elles effectueraient la tâche longue). Depuis la version 0.3, vous pouvez demander l'état d'un travailleur, ce qui vous permet d'afficher de jolies barres de progression.

Une autre caractéristique intéressante de Workling est que le backend asynchrone peut être changé : vous pouvez utiliser DelayedJobs, Spawn (fork classique), Starling...

6voto

Sarah Mei Points 10673

J'ai un site à très gros volume qui génère beaucoup de gros fichiers CSV. Ceux-ci prennent parfois plusieurs minutes pour être complétés. Je procède comme suit :

  • J'ai un tableau des emplois avec les détails du fichier demandé. Lorsque l'utilisateur demande un fichier, la demande est placée dans ce tableau et l'utilisateur est dirigé vers une page "état des travaux" qui répertorie tous ses travaux.
  • J'ai une tâche rake qui exécute tous les travaux en cours (une méthode de classe sur le modèle de travail).
  • J'ai une installation séparée de rails sur une autre boîte qui gère ces travaux. Cette boîte ne fait que des travaux et n'est pas accessible au monde extérieur.
  • Sur cette boîte séparée, un travail cron exécute tous les travaux en cours toutes les 60 secondes, à moins que les travaux soient encore en cours d'exécution depuis la dernière invocation.
  • La page d'état du travail de l'utilisateur se rafraîchit automatiquement pour afficher l'état du travail (qui est mis à jour par la boîte des travaux au fur et à mesure que le travail est lancé, exécuté, puis terminé). Une fois le travail terminé, un lien apparaît vers le fichier de résultats.

Elle est peut-être trop lourde si vous ne prévoyez d'en faire fonctionner qu'une ou deux à la fois, mais si vous voulez changer d'échelle... :)

4voto

Appeler ./script/runner en arrière-plan a fonctionné au mieux pour moi. (Je faisais également de la génération de PDF.) Cela semble être le plus petit dénominateur commun, tout en étant le plus simple à mettre en œuvre. Voici un compte rendu de mon expérience .

2voto

John Topley Points 58789

Une solution simple qui ne nécessite pas de Gems ou de plugins supplémentaires serait de créer une tâche Rake personnalisée pour gérer la génération du PDF. Vous pourriez modéliser le processus de génération PDF comme une machine à états avec des états tels que soumis , traitement y complet qui sont stockées dans la table de la base de données du modèle. La requête HTTP initiale de l'application Rails ajouterait simplement un enregistrement à la table avec une balise soumis l'état et le retour.

Il y aurait un travail cron qui exécute votre tâche Rake personnalisée en tant que processus Ruby distinct, de sorte que l'application Rails principale n'est pas affectée. La tâche Rake peut utiliser ActiveRecord pour trouver tous les modèles qui ont l'attribut soumis changer l'état en traitement et ensuite générer les PDFs associés. Enfin, il doit définir l'état à complet . Cela permet à vos appels AJAX dans l'application Rails de surveiller l'état du processus de génération du PDF.

Si vous placez votre tâche Rake dans votre_application_rails /lib/tasks alors il a accès aux modèles de votre application Rails. Le squelette d'une telle pdf_generator.rake ressemblerait à ceci :

namespace :pdfgenerator do
  desc 'Generates PDFs etc.'
  task :run => :environment do

    # Code goes here...
  end
end

Comme indiqué dans le wiki, il y a quelques inconvénients à cette approche. Vous utiliserez cron pour créer régulièrement un processus Ruby assez lourd et le timing de vos tâches cron devra être soigneusement réglé pour garantir que chacune d'entre elles ait suffisamment de temps pour se terminer avant que la suivante n'arrive. Cependant, l'approche est simple et devrait répondre à vos besoins.

2voto

TheMouseMan Points 272

Ce fil semble assez ancien. Cependant, ce que j'ai mis en place dans mon application, qui nécessite l'exécution de multiples Comptes à rebours pour différentes pages, était d'utiliser Fil de rubis . Le minuteur doit continuer à fonctionner même si la page a été fermée par les utilisateurs.

Ruby permet d'écrire facilement des programmes multithreads grâce à la classe Thread. Les threads Ruby sont un moyen léger et efficace d'obtenir du parallélisme dans votre code. J'espère que cela aidera d'autres personnes qui cherchent à atteindre le parallélisme/les services simultanés dans leur application. De même, Ajax rend beaucoup plus facile l'appel d'une action [personnalisée] spécifique de Rails à chaque seconde.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X