【问题标题】:Rails background image upload causing application timeoutRails背景图片上传导致应用程序超时
【发布时间】:2014-11-07 02:05:54
【问题描述】:

不幸的是,对于那些有类似问题的人来说,赏金奖励给了一个不能解决这个问题的答案。

我有一个带有图片上传的表单(heroku 到 s3)。当我提交表单时,我的 Rails 服务器会等待上传图像的后台作业完成,然后再向用户返回响应。这会导致每次上传图片时应用程序超时。

当前事件顺序:

  1. 用户提交表单
  2. 服务器接收表单
  3. 如果有图片,服务器启动后台作业
  4. 如果后台作业已启动,服务器会等待它完成(rails 在此处超时
  5. 如果启动,后台作业完成
  6. 服务器处理请求
  7. 服务器响应用户

所需的事件顺序:

  1. 用户提交表单
  2. 服务器接收表单
  3. 服务器处理非图像字段
  4. 如果有图片,服务器启动后台作业
  5. 服务器响应用户
  6. 后台作业完成,服务器处理上传的图片(保存 URL)

上传代码

class PhotoUploader < CarrierWave::Uploader::Base
  include ::CarrierWave::Backgrounder::Delay
  include CarrierWave::MimeTypes
  process :set_content_type
  storage :fog
end

Carrierwave::Backgrounder 初始化器

CarrierWave::Backgrounder.configure do |c|
  c.backend :sidekiq, queue: :carrierwave
end

用户模型

class User < ActiveRecord::Base
  mount_uploader :photo, PhotoUploader, delayed: true
  process_in_background :photo
end

没有控制器代码,因为表单由 ActiveAdmin 处理。我可以在需要的地方覆盖,但无法弄清楚需要改变什么。

要获得正确的事件顺序,我必须进行哪些更改?

【问题讨论】:

  • 如果我完全误解了这个问题,请原谅我,但是如果通过标准 HTML 表单提交完成,上传不会是异步的吗?这不需要一些javascript来异步处理上传,像这样吗? github.com/JangoSteve/remotipart
  • 我看过的所有关于异步图片上传的教程和资源都没有改变生成的 HTML 表单,只是控制器。正如我提到的图片上传工作正常。处理表单的控制器不需要等待。
  • 抱歉,我需要查看更多代码才能了解您是如何尝试实现这一点的。 sidekiq 工作人员是在处理整个上传到 S3 的过程,还是在上传完成后排队处理数据库更新?响应表单提交的控制器是什么样的?
  • 这些应该都不重要,因为一切正常。我只需要控制器不等待异步图像上传。 ActiveAdmin 正在使用标准上传器 (carrierwave) 处理表单。除了 ActiveAdmin 之外,此设置绝对没有什么特别之处。
  • 所以你的意思是使用非 ActiveAdmin 设置,标准 Rails 控制器(直接或间接)从 ActionController::Base 继承,上传将异步工作,控制器操作不会阻塞,直到上传完成了吗?

标签: ruby-on-rails carrierwave sidekiq


【解决方案1】:

这里的根本问题是 Heroku 对请求可以阻塞多长时间而不将数据发送回客户端有严格的限制。如果您达到该限制(初始字节为 30 秒),Heroku 将使您的请求超时。对于文件上传,您很可能会达到此限制。

最好的方法是让用户的浏览器先将文件直接上传到 S3。这里有一些与此相关的讨论:Direct Uploads to S3 using Carrierwave

如果您使用 jQuery File Upload 插件 (https://github.com/blueimp/jQuery-File-Upload) 之类的东西,流程将类似于:

  • 用户在点击提交前向表单添加一个或多个文件。
  • 文件直接上传到 S3,并为每个文件添加一个文件上传令牌到您的表单。
  • 用户使用上传文件的令牌而不是文件的内容提交表单。
  • 服务器可以根据提交的令牌将文件移动到它们在 S3 中的真实位置。

这使您的网络服务器可以专注于处理请求,而不是阻止可能需要很长时间的文件上传。

由于 Heroku 的限制,这需要更多的工作 - 但最终我认为这是您避免超时限制的唯一选择。

另外,我建议您创建一个上传 S3 存储桶,然后设置一个 S3 生命周期策略来清除超过某个时间间隔的文件。当您进行直接文件上传时,通常会由于用户放弃等原因导致某些上传无法处理,因此生命周期负责清理这些文件。

【讨论】:

  • 我们不想为此使用 javascript/jQuery。理想情况下,我们可以在后台将文件上传到 s3 时修改请求处理以响应用户。
  • 如果您在 Heroku 上使用默认 Rails 服务器,则每个 dyno 限制为一个请求,因此您可以通过切换到每个 dyno 支持多个 Web 进程的 unicorn 或 puma 来执行线程方法。不过,从长远来看,最安全的方法是直接上传文件。我同意这不是很方便,但这只是使用 Heroku 的缺点之一。我刚刚也发现了他们的这篇文章 - devcenter.heroku.com/articles/…
  • 我们已经在使用 Unicorn,所以每个 dyno 的请求限制应该不是问题。您链接的文章使用 jQuery 解决方案 =/
猜你喜欢
  • 2012-09-25
  • 2011-03-24
  • 2013-06-30
  • 1970-01-01
  • 2016-10-30
  • 1970-01-01
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多