rails异步作业如何让控制器知道它已经完成了?

时间:2015-02-02 15:26:11

标签: ruby ruby-on-rails-4 rails-activejob sucker-punch

我正在使用最新版本的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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:0)

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操作。作业完成后,它将提醒用户并在新选项卡中弹出已完成的作业。