Rails在Controller

时间:2017-03-22 12:25:52

标签: ruby-on-rails

当调用Controller中的路径时,我需要执行三项任务。现在我的代码看起来像这样(缩写):

 def set_quotas

    TaskOne.new().ex
    TaskTwo.new().ex
    TaskThree.new().ex

    quotas = @user.quotas
    render json: quotas, status: 200, each_serializer: Api::V1::QuotaSerializer
  end

每个任务按顺序运行。但是,其中一些人呼叫外部服务。因此,完成此调用所需的总时间最终为4-8秒,我们确实希望加快这一速度。

我想要做的是同时运行所有三个任务,但在呈现json响应之前,请等待每个任务完成。在Rails中实现这一目标的最佳方法是什么?

1 个答案:

答案 0 :(得分:4)

您可以使用threads

这是一个简单的解决方案:

def set_quotas
  [
    Thread.new { TaskOne.new().ex },
    Thread.new { TaskTwo.new().ex },
    Thread.new { TaskThree.new().ex }
  ].each &:join

  quotas = @user.quotas
  render json: quotas, status: 200, each_serializer: Api::V1::QuotaSerializer
end

然而,在Ruby中使用并发时需要注意几点。首先也是最重要的是,当您使用线程时,您将受到并发性带来的所有复杂问题的影响。期待头痛。并发可以很快地混淆简单的任务。例如,对于您的问题,您需要确保您的三个任务真正独立。一个任务是否依赖于另一个任务的输出?有人有副作用吗?比如,是否有人将一些数据写入后续作业所依赖的数据库?如果是这种情况,那么上述内容将无效,您需要弄清楚如何适应其特​​定的相互依赖关系。

其次,ruby线程为green threads。 (假设你使用的是MRI Ruby,而不是Rubinius或JRuby。)这意味着如果你只为某些任务获得ruby线程的加速。幸运的是,Web请求是阻止ruby线程的事情之一,这意味着上述解决方案同时发出所有请求。你应该看到这个解决方案的加速。

最后,这有点特定于您的用例,当您的应用向第三方发出呼叫时,通常最好将这些内容转发给工作人员。对第三方的调用容易出错,并且很难向客户端返回400秒(500秒,如果你不小心处理错误!)。最好将该工作放入队列中,并给客户一个基本上说“得到请求,稍后会做的”的响应。

鉴于这一切,如果您发现需要比本机ruby线程更强大的东西,请查看concurrent-ruby gem。

@ AbM的回答提到了Resque / DJ。有关更一般的解决方案,请查看ActiveJob。对于某些(但不是全部)变体,请参阅ActiveJob adapter list

相关问题