2016-11-08 1 views
0

J'utilise des rails avec ActiveJob et sidekiq comme backend. Lorsque l'utilisateur arrive sur une page sidekiq créer une tâche d'arrière-plan à long terme, comment puis-je remarquer un utilisateur (en rendant partiel sur la page Web) quand une tâche serait terminée? Rails et sidekiq fonctionnent comme différents processus.Comment notifier un utilisateur après la fin de la tâche en arrière-plan?

Ce fait m'a troublé Je ne comprends pas comment gérer le statut complet en utilisant le travail de fond.

Répondre

3

ActiveJob fournit un rappel after_perform qui, selon docs fonctionne comme ceci:

class VideoProcessJob < ActiveJob::Base 
    queue_as :default 

    after_perform do |job| 
    UserMailer.notify_video_processed(job.arguments.first) 
    end 

    def perform(video_id) 
    Video.find(video_id).process 
    end 
end 

Donc, vous n'avez pas à vous soucier d'intégrer directement avec Sidekiq ou tout autre backend faire la queue, parler à ActiveJob :)

+0

Thx, mais je tiens à remarquer l'utilisateur par rendre partiel sur la page Web – mystdeim

+1

@mystdeim le problème ici est quelle page web! l'utilisateur aurait pu aller à n'importe qui droit? tout rendu/redirection qui pourrait être possible ne sera pas une bonne idée. Utilisez plutôt une modalité de notification déclenchée par l'abonnement 'ActionCable'. Je vais essayer de poster du code mais ça ne devrait pas être dur. Bonne chance – Nimir

1

Mon approche dans cette situation est:

  1. Ajouter sidekiq-status afin que backg Les travaux ronds peuvent être suivis par ID.
  2. Dans l'appel client qui crée le travail d'arrière-plan, renvoyez l'ID du travail nouvellement créé.

    class MyController < ApplicationController 
    
        def create 
        # sidekiq-status lets us retrieve a unique job ID when 
        # creating a job 
        job_id = Workers::MyJob.perform_async(...) 
    
        # tell the client where to find the progress of this job 
        return :json => { 
         :next => "/my/progress?job_id={job_id}" 
        } 
        end 
    
    end 
    
  3. Poll un critère de 'progrès' sur le serveur avec cet ID d'emploi. Ce point de terminaison récupère les informations de progression du travail pour le travail et les renvoie au client.

    class MyController < ApplicationController 
    
        def progress 
        # fetch job status from sidekiq-status 
        status = Sidekiq::Status::get_all(params[:job_id]) 
    
        # in practice, status can be nil if the info has expired from 
        # Redis; I'm ignoring that for the purpose of this example 
    
        if status["complete"] 
         # job is complete; notify the client in some way 
         # perhaps by sending it a rendered partial 
         payload = { 
         :html => render_to_string({ 
          :partial => "my/job_finished", 
          :layout => nil 
         }) 
         } 
        else 
         # tell client to check back again later 
         payload = {:next => "/my/progress?job_id={params[:job_id]}"} 
        end 
    
        render :json => payload 
        end 
    
    end 
    
  4. Si le client voit que le travail est terminé, il peut alors afficher un message ou prendre toute prochaine étape est nécessaire.

    var getProgress = function(progress_url, poll_interval) { 
        $.get(progress_url).done(function(progress) { 
        if(progress.html) { 
         // job is complete; show HTML returned by server 
         $('#my-container').html(progress.html); 
        } else { 
         // job is not yet complete, try again later at the URL 
         // provided by the server 
         setTimeout(function() { 
         getProgress(progress.next, poll_interval); 
         }, poll_interval); 
        } 
        }); 
    }; 
    $("#my-button").on('click', function(e) { 
        $.post("/my").done(function(data) { 
        getProgress(data.next, 5000); 
        }); 
        e.preventDefault(); 
    }); 
    

caveat emptor: ce code est destiné à illustrer, et il manque des choses que vous devez prendre soin de tels que la gestion des erreurs, ce qui empêche les soumissions en double, et ainsi de suite.

+0

Vous faites cela de façon obsolète avec la mise en commun et préférez push-notify avec websocket ou SSE – mystdeim

+0

@mystdeim pouvez-vous partager un exemple de faire cela plus élégamment avec websockets/SSE? (J'essaie de trouver le meilleur moyen d'y parvenir, mais je ne trouve malheureusement pas beaucoup d'exemples en ligne) – gingerlime