2012-11-14 12 views
6

Diciamo che ho un'applicazione per blog con post. Dopo aver creato un post, viene creato un worker per gestire alcune operazioni in background. Il mio caso è che dopo aver inviato un modulo di posta voglio visualizzare qualche tipo di messaggio di caricamento (caricatore gif o simile) e quando l'operatore termina voglio nascondere il messaggio di caricamento e visualizzare alcuni dati forniti dall'operatore. La mia domanda è qual è il modo migliore per comunicare che un lavoratore ha finito il suo lavoro e lo mostra sul frontend per l'utente. Worker richiamata simile a questaBackground worker view communication in rails app

def worker_finish 
    #message the user 
end 

risposta

11

Penso che si può mancare il punto di avere lavoratori di fondo, in fondo, quello che si sta tentando di fare è controproducente. - Se l'utente invia il modulo e si accoda il lavoro nel controller, solo per fare in modo che l'utente attenda l'avvio e il completamento dell'operatore, non solo si è realizzato esattamente ciò che il controller avrebbe potuto fare da solo, ma si è ha reso il processo molto più complicato (e questo tipo di funzionalità non è integrato in resque o sidekiq).

Quando scarico un lavoro per essere elaborati da una coda che si desidera restituire una risposta al client immediatamente, vale a dire

class PostsController < ApplicationController 
    def create 
    @post = Post.create(params[:post]) 
    BackgroundBlogOperation.enque(@post.id) 
    respond_with(@post) 
    end 
end 

La classe BackgroundBlogOperation sarebbe poi essere collocato in una coda, per un lavoratore di passare attraverso e lavorare fuori. Se è necessario che l'operatore di BackgroundBlogOperation faccia qualcos'altro dopo averlo terminato, è possibile farlo, ma ciò dovrebbe avvenire all'interno del lavoro stesso, in modo che il lavoratore possa essere responsabile di ciò.

Se si sta solo tentando di visualizzare e nascondere lo spinner dopo aver creato un post, senza ricaricare la pagina, è sufficiente visualizzare lo spinner javascript prima del clic del pulsante di invio e assicurarsi che il tipo di richiesta sia js (aggiungere: remote = > true to form). Quindi creare una vista risposta javascript che assomiglia:

class PostsController < ApplicationController 
    respond_to :js, :only => [:create] 
    def create 
    @post = Post.create(params[:post]) 
    BackgroundBlogOperation.enque(@post.id) 
    respond_with(@post) 
    end 
end 

E il create.js.erb, potrebbe anche aggiungere un messaggio dicendo loro che tutto ciò che si sta facendo in background è stato in coda, se il suo più complesso rispetto alla creazione di un post o qualsiasi altra cosa

$("#spinner").hide(); 

ora - Anche se quello che stavi chiedendo originariamente doesent servire qualsiasi scopo (perché per visualizzare e nascondere la filatrice al termine del lavoro richiederebbe in attesa per il controller per completare l'azione) - Ci sono situazioni in cui è utile mostrare al cliente che il processo ha terminato l'elaborazione.

Prima consente di definire uno scenario in cui l'elaborazione in background è effettivamente utile. Diciamo che hai un pulsante che quando fai clic, inserirà i dati da qualche API esterna e, dopo aver ottenuto i dati dal sito esterno, eseguirai un'operazione di database basata sulla risposta. Questo sarebbe un buon esempio di quando utilizzare il processo in background. In sostanza nel regolatore si farebbe qualcosa di simile:

class ApiController < ApplicationController 
    respond_to :js, :only => [:create] 

    def sync_tweets 
    TwitterApiJob.enque(current_user.twitter_username) 
    respond_with(message: 'Syncing Tweets') 
    end 

end 

Ora, per informare l'utente quando i tweets hanno finito la sincronizzazione è un po 'più complicato, e si dispone di 3 opzioni di base:

1) Notifica degli utenti via email (generalmente l'opzione peggiore imo) 2) Utilizzare una sorta di server html5 o websocket rails capace di eseguire le rotaie e inviare una spinta attraverso il websocket al client, che sebbene molto interessante, è nella maggior parte dei casi eccessivo e al di fuori dell'ambito di questa risposta. Google rotaie websocket che spingono se vuoi vedere le tue opzioni. 3) IMO migliore opzione per la maggior parte dei casi, creare un modello notifcations per gestire tutti i tipi di notifiche degli utenti, e nel vostro lavoro, dopo che il lavoro è completo, fare qualcosa di simile

Notification.create(:user_id => user.id, :message => 'Sync has finished', type => 'sync_complete') 

Poi, pagina seguente le richieste degli utenti , in alto nella barra degli strumenti di intestazione o dovunque, avrei un avviso che l'utente ha notifiche non lette, per avvisare l'utente di cliccarci sopra.

--- Inoltre, penso che nel tuo post hai menzionato che stai utilizzando resque. Ho provato a resque ed è stato decente, ma ho trovato che è complicato fare il debug in produzione, e ha usato una memoria pazzesca - ti consiglio di controllare sidekiq se non lo hai già fatto, usa anche i redis ma molto più velocemente in quanto usa discussioni:

https://github.com/mperham/sidekiq

è molto più veloce, più pulito e facile da ottenere l'installazione, imho.

+0

Mentre il caso di utilizzo presentato potrebbe non essere l'ideale, la funzionalità potrebbe essere molto utile per l'esecuzione di un report, ad esempio. – aaandre

Problemi correlati