如何在Heroku中处理长Web请求?

时间:2012-12-30 04:59:17

标签: ruby-on-rails-3 heroku controller timeout httprequest

https://devcenter.heroku.com/articles/request-timeout


30秒,超时错误根据文档触发。

我正在上传并解析CSV文件以保存到我的数据库。其中一个文件大小为1.7MB,有37000行。

此过程需要一段时间才能处理,当然超过30秒。

在这些情况下我该怎么办?我有什么选择?

require 'csv'

class DatabaseImporterController < ApplicationController
  def index
  end

  def import
    # Receive the uploaded CSV file and import to the database.
    csv_file = params[:csv_file].tempfile

    i = 0
    CSV.foreach(csv_file) do |row|
      # Structure for CSV file: Year, Make, Model, Trim
      if i > 0 then
        make = Make.find_or_create_by_name(row[1])
        model = make.model.create(:year => row[0], :name => row[2], :trim => row[3])
      end

      i += 1
    end
    redirect_to :action => 'list'
  end

  def list
    @models = Model.all
  end
end

1 个答案:

答案 0 :(得分:3)

不是在控制器中处理CSV文件,而是将通知推送到具有上载文件位置的队列。然后有一个worker dyno句柄处理。

你需要付出更多,特别是如果你想要坚持免费的单一dyno层,但这是一个可扩展的设计(这就是为什么我想象HTTP处理有30秒的超时)

另一种方法是将数据直接推送到表中并异步执行存储过程。这会将工作推迟到Postgres来处理HTTP线程,并且可能会将您的请求置于30秒的时间限制之内,但是如果使用较大的文件,您可能无论如何都可以使用此权限。

在您重新构建整个应用程序you'll want to run a test之前,确保Heroku未禁用libpq-asynch

上面代码中的大成本是Make.find_or_create_by_name,它根据您的示例输入调用37,000个单独的SELECT,并且可能是CSV中每行的INSERT。如果libpq-asynch不是一个选项,你将不得不创建一个存储过程,它将一次批量生成100或1000行 - 这样你的控制器代码就不会进行如此多的数据库往返。 Postgres支持经典序数索引样式中的arrays以及row types的数组,所以这实际上比听起来要痛苦得多。