2009-05-22 5 views
28

Lorsqu'une nouvelle ressource est créée et il a besoin de faire un peu long traitement avant que la ressource est prêt, comment puis-je envoyer que le traitement loin dans l'arrière-plan où il ne tiendra pas la demande actuelle ou autre le trafic vers mon application Web?Ruby on Rails: Comment faire fonctionner les choses en arrière-plan?

dans mon modèle:

class User < ActiveRecord::Base 
after_save :background_check 

protected 
def background_check 
    # check through a list of 10000000000001 mil different 
    # databases that takes approx one hour :) 
    if(check_for_record_in_www(self.username)) 
    # code that is run after the 1 hour process is finished. 
    user.update_attribute(:has_record) 
    end 
end 
end 

Répondre

39

Vous devriez certainement vérifier les Railscasts suivants:

Ils expliquent comment exécuter les processus d'arrière-plan dans Rails dans tous les possibles manière (avec ou sans aq ueue ...)

+2

Ces jours-ci, les options les plus utilisées/les mieux pris en charge sont [sidekiq] (https://github.com/mperham/sidekiq), [resque ] (https://github.com/defunkt/resque) et [delayed_job] (https://github.com/collectiveidea/delayed_job). À mon humble avis, Sidekiq est le meilleur pour les files d'attente à haut débit, et delayed_job est le meilleur pour un très faible débit. –

+0

Une autre option est [IronWorker] (http://www.iron.io) si vous voulez un traitement en arrière-plan "en tant que service" et ne jamais avoir à vous soucier de l'idée de serveurs ou de files d'attente. IronMQ/IronWorker propose également des tentatives automatiques, des journaux de tâches, des webhooks, etc. Il s'intègre parfaitement avec Rails. Voici quelques vidéos: https://www.youtube.com/user/ironiodevelopers – Chad

7

Démarrer un processus distinct, ce qui est probablement le plus facile à faire avec system, préfixant « nohup » et annexant un « & » à la fin de la commande que vous passez. (Assurez-vous que la commande est juste un argument de chaîne, pas une liste d'arguments.)

Il y a plusieurs raisons pour lesquelles vous voulez le faire de cette façon, plutôt que, par exemple, en essayant d'utiliser des fils:

  1. Les threads de Ruby peuvent être un peu compliqués quand il s'agit de faire des E/S; vous devez veiller à ce que certaines choses que vous faites ne bloquent pas l'ensemble du processus. Si vous exécutez un programme avec un nom différent, il est facilement identifiable dans 'ps', donc vous ne pensez pas accidentellement que c'est un back-end FastCGI qui est devenu sauvage ou quelque chose, et le tuez.

Vraiment, le processus de commencer devrait être « deamonized, » voir la classe Daemonize de l'aide.

2

Vous souhaitez idéalement utiliser un serveur de travaux d'arrière-plan existant plutôt que d'écrire le vôtre. ceux-ci vous permettent généralement de soumettre un travail et de lui donner une clé unique; Vous pouvez ensuite utiliser la clé pour interroger périodiquement le Job Server sur l'état de votre travail sans bloquer votre application Web. here is a nice roundup des différentes options là-bas.

0

Qu'en est-:

def background_check 
    exec("script/runner check_for_record_in_www.rb #{self.username}") if fork == nil 
end 

Le programme « check_for_record_in_www.rb » sera ensuite exécuter dans un autre processus et auront accès à ActiveRecord, pouvoir accéder à la base de données.

1

J'aime utiliser backgroundrb, c'est sympa cela vous permet de communiquer avec lui pendant de longs processus. Donc, vous pouvez avoir des mises à jour de statut dans votre application rails

1

Je pense que spawn est un excellent moyen de bifurquer votre processus, de faire un peu de traitement en arrière-plan et de montrer à l'utilisateur une confirmation que ce traitement a été démarré.

6

Je viens d'expérimenter avec la gemme 'delayed_job' car elle fonctionne avec la plate-forme d'hébergement Heroku et c'était ridiculement facile à installer !!

Ajouter bijou à Gemfile, bundle install, rails g delayed_job, rake db:migrate Lancez ensuite un gestionnaire de file d'attente avec;

RAILS_ENV=production script/delayed_job start 

Si vous avez un appel de méthode qui est votre processus de longue haleine i.e.

company.send_mail_to_all_users 

vous changez à;

company.delay.send_mail_to_all_users 

Vérifiez les documents complets sur github: https://github.com/collectiveidea/delayed_job