我正试图将文件下载分解为后台进程。我的资产存储在S3上。
我的原始(阻塞)代码看起来像这个
# From DownloadsController#download
data = open(path)
send_data(data.read, type: @download.mime_type, filename: @download.file_title)
所以我设置了Redis和Sidekiq,并创建了一个FielDownloadWorker
:
class FileDownloadWorker
include Sidekiq::Worker
def perform(path, mime_type, file_title)
data = open(path)
# What happens next?
end
end
这被称为使用:
FileDownloadWorker.perform_async(路径,@download.mime_type,@download.file_title)
如何从工作人员启动下载
你不能。您希望用户接收该文件,对吗?它必须在控制器内发生,以便控制器能够通过下载来响应。如果您试图实现并发,请尝试使用线程:
@data = nil
t = Thread.new { @data = open(path) }
# ... do other stuff ...
t.join # wait for download to finish in other thread
send_data(@data.read, type: @download.mime_type, filename: @download.file_title)
如果你决定采用worker方法,你可以让它在下载完成时更新数据库字段或缓存,那么用户必须向你的应用程序发出另一个请求才能获得完成的文件。类似于:
- 用户单击按钮启动下载
- 页面更新消息"您的文件正在下载,几秒钟后刷新页面"
- 用户刷新页面,控制器看到文件已下载并执行
send_data
我最终使用查询字符串身份验证直接从S3启动了文件下载。通过这种方式,文件从S3直接下载到客户端,Rails应用程序的线程不会被阻塞。
这里写得很棒。