2016-11-08 4 views
0

私はバックエンドとしてActiveJobsidekiqのレールを使用します。ユーザーがページsidekiqに来たら、長期的なバックグラウンドタスクを作成します。タスクが完了すると、どのようにユーザーに気付くことができますか?バックグラウンドタスクが完了した後にユーザーに通知する方法はありますか?

Railsとsidekiqは異なるプロセスとして動作します。この事実は私を混乱させました。私はバックグラウンドジョブを使用して完了ステータスを処理する方法を理解していません。

答えて

3

ActiveJobドキュメントによるとafter_performコールバックは次のように動作提供:だから

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 

、あなたがActiveJobに話し、Sidekiqまたは任意の他のキューイングのバックエンドと直接統合するために心配する必要はありません:)

+0

Thx、しかし私はウェブページのレンダリング部分でユーザに気づきたい – mystdeim

+1

@mystdeimここの問題はどのウェブページです!ユーザーは誰にでも右に行ったことがありますか?可能なレンダー/リダイレクトは良い考えではありません。代わりに、 'ActionCable'サブスクリプションによって起動された通知モーダルを使用してください。いくつかのコードを投稿しようとしますが、難しくはありません。幸運 – Nimir

1

このような状況で私のアプローチは、次のとおりです。

  1. ようにバックグラウンド・をsidekiq-statusを追加IDで追跡することができます。
  2. バックグラウンドジョブを作成するクライアント呼び出しでは、新しく作成したジョブのIDを返します。

    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. そのジョブIDを持つサーバー上の「進行」エンドポイントをポーリングします。このエンドポイントは、ジョブのジョブ進捗情報を取り出し、クライアントに返します。

    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. クライアントは、ジョブが完了したことを認識した場合、それは、メッセージを表示したり、次のステップが必要とされるものは何でも取ることができます。

    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(); 
    }); 
    

警告の買い手:そのコードは例示であることを意味する、とあなたはなど、重複送信を防止し、エラー処理などの世話をする、とすべきものが欠落しています。

+0

あなたはプーリングで時代遅れのやり方でこれを行い、websocketまたはSSEでpush-notifyを好む – mystdeim

+0

@mystdeim websockets/SSEでこれをもっとうまくやっている例を共有できますか? (私はこれを達成する最良の方法を理解しようとしていますが、残念ながら多くの例をオンラインで見つけることはできません) – gingerlime

関連する問題