我使用rails与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
因此,您不必担心直接与Sidekiq
或任何其他排队后端集成,请与ActiveJob
交谈:)
在这种情况下我的方法是:
- 添加sidekiq-status以便可以通过ID跟踪后台作业。
-
在创建后台作业的客户端调用中,返回新创建的作业的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轮询服务器上的'progress'端点。此端点获取作业的进度信息并将其返回给客户端。
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(); });
请注意:这段代码是为了说明问题,并且遗漏了一些您应该注意的事情,例如错误处理、防止重复提交等等。