2009-05-22 14 views
28

Quando si crea una nuova risorsa e ha bisogno di fare un po 'lunga elaborazione prima che la risorsa è pronta, come faccio a inviare che l'elaborazione via in secondo piano dove non terrà fino la richiesta corrente o altro traffico verso la mia web-app?Ruby on Rails: come eseguire le cose in background?

nel mio modello:

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 

risposta

39

si dovrebbe verificare le seguenti Railscasts:

spiegano come eseguire i processi in background in Rails in ogni possibile modo (con o senza aq ueue ...)

+2

In questi giorni, le opzioni/best-supportate più utilizzati sono [sidekiq] (https://github.com/mperham/sidekiq), [Resque ] (https://github.com/defunkt/resque) e [delayed_job] (https://github.com/collectiveidea/delayed_job). IMHO, Sidekiq è il migliore per le code ad alto throughput e delayed_job è il migliore per un throughput molto basso. –

+0

Un'altra opzione è [IronWorker] (http://www.iron.io) se si desidera l'elaborazione in background "come servizio" e non bisogna mai preoccuparsi dell'idea di server o di accodamento. IronMQ/IronWorker offre anche tentativi automatici, registri delle attività, webhook, ecc. Si integra perfettamente con Rails. Ecco alcuni video: https://www.youtube.com/user/ironiodevelopers – Chad

7

avviare un processo separato, che è probabilmente il più facilmente fatto con system, anteponendo un 'nohup' e aggiungendo un '&' alla fine del comando si passa. (Assicurarsi che il comando è solo un argomento stringa, non un elenco di argomenti.)

Ci sono diversi motivi che si desidera fare in questo modo, piuttosto che, diciamo, cercando di utilizzare le discussioni:

  1. I thread di Ruby possono essere un po 'complicati quando si tratta di fare I/O; devi fare attenzione che alcune cose che fai non causino il blocco dell'intero processo.

  2. Se si esegue un programma con un nome diverso, è facilmente identificabile in "ps", quindi non si pensa accidentalmente che sia un back-end FastCGI impazzito o qualcosa del genere e lo uccida.

In realtà, il processo si avvia dovrebbe essere "deamonized," vedere la classe Daemonize per chiedere aiuto.

2

idealmente si desidera utilizzare un server di lavoro in background esistente anziché crearne uno proprio. questi in genere ti consentono di inviare un lavoro e dargli una chiave univoca; puoi quindi utilizzare la chiave per interrogare periodicamente il server di lavoro per lo stato del tuo lavoro senza bloccare la tua webapp. here is a nice roundup delle varie opzioni disponibili.

0

Che dire:

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

Il programma "check_for_record_in_www.rb" sarà quindi eseguire in un altro processo e avranno accesso a ActiveRecord, essendo in grado di accedere al database.

1

Mi piace usare backgroundrb, è bello che ti permette di comunicare durante lunghi processi. Quindi è possibile avere aggiornamenti di stato nell'app rotaie

1

Penso che spawn sia un ottimo modo per eseguire il processo, eseguire alcune operazioni in background e mostrare all'utente solo alcune conferme dell'avvio di questa elaborazione.

6

Ho appena sperimentato la gemma "delayed_job" perché funziona con la piattaforma di hosting Heroku ed è stato incredibilmente facile da configurare !!

Aggiungi gioiello da Gemfile, bundle install, rails g delayed_job, rake db:migrate quindi avviare una coda con gestore;

RAILS_ENV=production script/delayed_job start 

Dove si dispone di una chiamata di metodo che è il vostro processo lungo cioè

company.send_mail_to_all_users 

si cambia a;

company.delay.send_mail_to_all_users 

Controllare la documentazione completa su GitHub: https://github.com/collectiveidea/delayed_job