2

我正在使用最新版本的 rails 和 ruby​​。通过一个表单,我导入了一个 CSV,然后触发了一个异步作业(我为此使用了 gem https://github.com/brandonhilkert/sucker_punch)来读取文件并处理数据。

总而言之,一切正常,但是:

我的问题是,我如何让控制器知道后台工作何时完成?我想通过快速通知重定向,但显然我不应该从模型中这样做......我可以在这里做什么?

这是我的sucker_punch 工作:

#app/jobs/import_job.rb

class ImportJob
  include SuckerPunch::Job

  def perform(import_file)
    ActiveRecord::Base.connection_pool.with_connection do
      ModelName.import_from_csv(import_file)
    end
  end
end

这是我的控制器操作:

def import
  ImportJob.new.async.perform(import_file)
  redirect_to list_data_path, notice: 'Data being imported...'
  # i get sent to list_data_path and i stay there even though the background job already finished successfully
end
4

2 回答 2

3

对于这种任务,我将创建一个模型 (ActiveRecord),它保存作业的状态(等待、处理、完成,可能还有进度),并从控制器查询模型以呈现给使用导入作业状态。

于 2015-02-02T17:39:55.417 回答
1

Web 应用程序严格按照“拉”模型运行。客户端发送请求,服务器响应。当您重定向到 list_data_path 时,这就是您的服务器响应。在收到另一个请求之前,您无法发送另一个响应。

这意味着,服务器无法联系客户端并说“嘿,我完成了!” 相反,您需要做的是在客户端放置一些 Javascript,它会询问服务器:“你完成了吗?” 这让服务器有机会回复“是的,我完成了”或“不,仍在工作”。

这是一个使用 JQuery 的简单示例:

function processJob(jobId) {
  $.ajax({
    url: "path/to/job/status/" + jobId,
    success: function(result) {
      alert("Job done!");
      window.location("path/to/completed/job/" + jobId);
    },
    error: function(req, statusText, err) {
      if(req.status == 202) 
        setTimeout(function() { processJob(jobId); }, 2000);
      }
      else { alert("Error processing job."); }
  });
}

在服务器端,path/to/job/status 应该是一个路由,如果作业仍在处理中,则呈现状态 202,如果作业完成,则呈现状态 200,如果作业遇到错误,则呈现状态 500。path/to/completed/job 应该是显示已完成作业结果的路由。

当用户初次提交要处理的文件时,在客户端调用该方法。它将默默地监视作业的状态,直到它完成,每 2 秒 ping 一次服务器。作业完成后,它将提醒用户并在新选项卡中弹出打开已完成的作业。

于 2015-08-06T18:13:26.910 回答