【发布时间】:2017-03-22 02:41:19
【问题描述】:
我使用带有ActiveJob 和sidekiq 的rails 作为后端。当用户来到一个页面sidekiq 创建一个长期后台任务时,我怎样才能注意到用户(通过在网页上呈现部分)何时完成任务?
Rails 和 sidekiq 作为不同的进程工作。这个事实让我很困惑,我不明白如何使用后台作业处理完成状态。
【问题讨论】:
标签: ruby-on-rails background-process sidekiq
我使用带有ActiveJob 和sidekiq 的rails 作为后端。当用户来到一个页面sidekiq 创建一个长期后台任务时,我怎样才能注意到用户(通过在网页上呈现部分)何时完成任务?
Rails 和 sidekiq 作为不同的进程工作。这个事实让我很困惑,我不明白如何使用后台作业处理完成状态。
【问题讨论】:
标签: ruby-on-rails background-process 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 交谈:)
【讨论】:
ActionCable 订阅触发的一些通知模式。将尝试发布一些代码,但这应该不难。祝你好运
我在这种情况下的做法是:
在创建后台作业的客户端调用中,返回新创建的作业的 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();
});
注意事项:该代码仅用于说明,缺少您应该注意的事项,例如错误处理、防止重复提交等。
【讨论】: