在rails中下载动态生成的大文件

时间:2016-01-11 19:27:03

标签: ruby-on-rails ruby-on-rails-4

我有一个包含大量行的大型数据库,用户在数据库上生成查询,然后想要导出信息(当前正在执行CSV)。问题是,随着我们的数据库不断增长,查询需要很长时间才能下载尝试超时。

如何创建Rails以便在创建时随时间下载文件?这些请求并不常见,所以我不介意对服务器进行严厉的打击,但它们确实需要动态(我不能提前生成文件)。

我发现很多关于如何在Rails中下载文件的网站,但它们要么处理已经创建的文件,要么处理那些没有时间创建的小文件。这些文件可能非常大(20MB +),所以他们需要“流式”下载,但我找不到某种方法。

3 个答案:

答案 0 :(得分:5)

我建议使用后台工作服务,例如延迟工作或者用于rails的sidekiq,

告诉您的用户他们的报告很快就会准备就绪,并将其安排到后台工作服务,在报告生成作业结束时向用户发起通知(websockets,电子邮件......),然后允许用户从您正在使用的任何存储中下载生成的文件 - 本地,S3等

这比流式传输大型响应有以下好处:

  1. 1位来自会计的用户想要制作他的季度报告捆绑的20份大型报告,不会因为工人用尽而冻结所有流量的网络主机,因此您的CEO仍然可以登录查看他的号码
  2. 您可以减少后台服务上的工作人员数量,因此当第1点的所述用户来访问您时,大型复杂查询不会压倒您的数据库
  3. 文件的提供将由您的服务或S3前面的Web服务器完成,而不是工作进程(rails可能很慢)

答案 1 :(得分:1)

如果您将nginx作为前端服务器,则可以使用出色的X-Accel-Redirect功能。

您可以使用后台作业(例如Sidekiq)来构建大文件而不会阻止您的Rails应用程序。生成文件后,您可以使用没有Rails应用程序的nginx来提供它。场景如:

  1. 根据用户的请求在后台作业中开始生成文件。返回工作ID(或其他任何识别工作的人)。
  2. 使用客户端轮询(例如,javascript ajax调用第一个请求中的job_id)来验证文件是否已创建。
  3. 创建文件后,返回' X-Accel-Redirect'标题由nginx加载文件。
  4. 用户将使用nginx下载文件。
  5. 使用此方案,您的应用程序在高负载方面可以是持久的。文件下载将由nginx处理,而不是由Rails应用程序处理。

答案 2 :(得分:1)

感谢所有建议,看起来非常可靠 - 但我最终创建了一个rake任务,生成文件并通过电子邮件发送给用户,并在用户点击下载按钮时将任务作为后台进程运行

从Sidekiq看,如果你有大量的下载和其他文件,这似乎是一个更好的选择 - 但我只有这个,所以这对我来说更快更容易,因为设置正确的Sidekiq不是一个简单的过程。