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

4
我有一个庞大的数据库,里面有很多行数据。用户会对这个数据库进行查询,然后希望导出信息(目前是使用CSV格式)。问题是,随着我们的数据库不断增长,查询所需时间太长,下载时常会超时。

我该如何设置Rails来在文件被创建时逐步下载它?这些请求并不常见,因此我不介意给服务器带来一定压力,但它们必须是动态的(我不能提前生成文件)。

我找到了很多关于如何在Rails中下载文件的网站,但它们要么涉及已经创建好的文件,要么涉及创建起来很快的小文件。这些文件可能非常大(20MB+),因此需要“流式”下载,但我无法找到任何可行的方法。


1
异步导出函数? - Mike K.
谷歌搜索“rails流式响应”,你会发现前两个链接与你的问题的流式部分相关。 - bbozo
3个回答

6
我建议使用后台工作服务,如延迟作业或rails的sidekiq。告诉用户他们的报告将很快准备好,并将其安排到后台工作服务中,在报告生成作业结束时向用户发出通知(WebSockets、电子邮件等),然后允许用户从您正在使用的任何存储中下载结果文件-本地、S3等。
这与流式传输大型响应相比具有以下优点:
1.来自会计部门的一个用户想要制作他的季度报告包括20个巨大的报告,不会因为工作者枯竭而冻结您的Web主机,因此您的CEO仍然可以登录查看他的数字。
2.您可以降低后台服务上的工作者数量,因此当上述第1点的用户来访问您时,大型复杂查询不会使您的数据库不堪重负。
3.文件的提供将由您的服务或S3前面的Web服务器完成,而不是工作进程(Rails可能较慢)。

1
如果您有nginx作为前置服务器,则可以使用强大的X-Accel-Redirect功能。您可以使用后台作业(例如Sidekiq)构建大文件,而不会阻塞Rails应用程序。生成文件后,您可以在没有Rails应用程序的情况下使用nginx提供服务。场景如下:
1. 在用户请求时在后台作业中启动文件生成。返回作业ID(或其他用于标识作业的内容)。 2. 使用客户端轮询(例如javascript ajax调用带有来自第一个请求的job_id)来验证是否已创建文件。 3. 当文件被创建时,返回“X-Accel-Redirect”头以通过nginx加载文件。 4. 用户将通过nginx下载文件。
使用此场景,您的应用程序可以在高负载方面持久存在。文件下载将由nginx处理,而不是由Rails应用程序处理。

1
感谢所有的建议,它们看起来相当可靠 - 但我最终创建了一个rake任务来生成文件并将其通过电子邮件发送给用户,并在用户单击下载按钮时作为后台进程运行该任务。
从查看Sidekiq的情况来看,如果您有大量下载和其他文件等需要担心的内容,那似乎是更好的选择 - 但我只有这一个,所以对我来说更快更容易,因为正确设置Sidekiq并不是一个简单的过程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接