私はバックエンドとしてActiveJob
とsidekiq
のレールを使用します。ユーザーがページsidekiq
に来たら、長期的なバックグラウンドタスクを作成します。タスクが完了すると、どのようにユーザーに気付くことができますか?バックグラウンドタスクが完了した後にユーザーに通知する方法はありますか?
Railsとsidekiqは異なるプロセスとして動作します。この事実は私を混乱させました。私はバックグラウンドジョブを使用して完了ステータスを処理する方法を理解していません。
私はバックエンドとしてActiveJob
とsidekiq
のレールを使用します。ユーザーがページsidekiq
に来たら、長期的なバックグラウンドタスクを作成します。タスクが完了すると、どのようにユーザーに気付くことができますか?バックグラウンドタスクが完了した後にユーザーに通知する方法はありますか?
Railsとsidekiqは異なるプロセスとして動作します。この事実は私を混乱させました。私はバックグラウンドジョブを使用して完了ステータスを処理する方法を理解していません。
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
または任意の他のキューイングのバックエンドと直接統合するために心配する必要はありません:)
このような状況で私のアプローチは、次のとおりです。
バックグラウンドジョブを作成するクライアント呼び出しでは、新しく作成したジョブの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
そのジョブ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
クライアントは、ジョブが完了したことを認識した場合、それは、メッセージを表示したり、次のステップが必要とされるものは何でも取ることができます。
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();
});
警告の買い手:そのコードは例示であることを意味する、とあなたはなど、重複送信を防止し、エラー処理などの世話をする、とすべきものが欠落しています。
あなたはプーリングで時代遅れのやり方でこれを行い、websocketまたはSSEでpush-notifyを好む – mystdeim
@mystdeim websockets/SSEでこれをもっとうまくやっている例を共有できますか? (私はこれを達成する最良の方法を理解しようとしていますが、残念ながら多くの例をオンラインで見つけることはできません) – gingerlime
Thx、しかし私はウェブページのレンダリング部分でユーザに気づきたい – mystdeim
@mystdeimここの問題はどのウェブページです!ユーザーは誰にでも右に行ったことがありますか?可能なレンダー/リダイレクトは良い考えではありません。代わりに、 'ActionCable'サブスクリプションによって起動された通知モーダルを使用してください。いくつかのコードを投稿しようとしますが、難しくはありません。幸運 – Nimir