如何从长时间运行的进程并行返回Rails ActionController的响应?

时间:2014-06-05 20:01:41

标签: ruby-on-rails ruby ruby-on-rails-3

我主要使用Node作为后端服务,但使用Ruby 1.9.3维护Rails 3.2 API。最近我们意识到在某些极端情况下,我们的FoosController#create控制器方法需要很长时间才能使客户端在收到响应之前超时。我有类似

的东西
def create
  if check_for_bad(params) # Validation step
    return bad_params_error # Return 400 error
  end

  Foo.create(params) # Need to move this to a parallel thread

  output = { status: 200, message: 'OK' }
  return render json:output
end

客户端在初始params检查后不需要知道任何错误,所以我想在运行Foo#create之前返回响应,但我确实需要将params传递给该方法。我尝试使用after_filter方法(尝试undefined method时得到after_action)。

看起来这应该很容易,可能是使用光纤或基于它构建的宝石,但我对可用的东西不够熟悉,以确保我做的工作没有造成比我更多的问题解决。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

正如@BroiSatse所提到的,我建议在Sidekiq的后台执行此操作。 Sidekiq上的指南给出了整体设置,但在这种情况下,你必须改变你对创建Foo意味着什么的一点想法。

你会立即创建一个状态为“pending”或其他东西的Foo,然后将你的params和创建的Foo id传递给后台工作者,这将完成艰苦的工作。如果一切都在那里成功,你会更新你的Foo“完成”或“准备好”。

要进行Foo创建后台工作,您需要创建一个worker:

# app/workers/CreateFooWorker.rb
class CreateFooWorker
  include Sidekiq::Worker

  def perform(foo_id, params)
    if foo = Foo.find(foo_id) && foo.update_attributes(params)
      foo.update_attribute(:state, "ready")
    end
  end
end

# Change create to immediately create a foo without the params
# and then actually build the real foo with params in the background
def create
  if check_for_bad(params) # Validation step
    return bad_params_error # Return 400 error
  end

  foo = Foo.create(state: "pending") # Just create with a pending state...
  CreateFooWorker.perform_async(foo.id, params) # Now do the real work in the background

  # You're going to want to retun the foo json here
  # because your client will need to hold onto the
  # foo.id and query the server for when the foo is "ready"
  return render json: foo.to_json, status: created
end