我想知道是否有人可以帮助我解决我遇到的流式下载问题?
目前,我有一个存储在 s3 存储桶中的大型 GZipped XML 文件,我需要每天使用 ruby 下载、解压缩和解析该文件。由于文件的大小,我选择以块的形式下载大文件并对每个块执行必要的解析,如下所示:
module S3Stream
def self.call(credentials)
Enumerator.new do |yielder|
connection = Fog::Storage.new(credentials)
bucket = connection.directories.new(key: 'bucket_name')
bucket.files.get('file_name.tar.gz') do |chunk, remaining_bytes, total_bytes|
yielder << chunk
end
end
end
end
返回 Enumerator 对象允许我稍后在脚本中处理块的每个部分(即解压缩并解析其中包含的 XML)
这一切都需要按计划运行,所以我有一个独立的 Heroku dyno 为我运行 ruby 脚本(我的 Rails 站点也部署到 Heroku)。它在本地运行良好,但在 Heroku 上运行大约一个小时后(有时取决于测功机的大小),脚本失败并显示以下错误消息:
Errno::ECONNRESET: Connection reset by peer
我的问题是,当这在我的流中间失败时,我不确定如何从连接重置的块开始重试下载。
Fog 的流下载文档很少,切换到适用于 Ruby 的 AWS 开发工具包似乎为块提供的信息更少(即没有剩余或总字节参数)。
有任何想法吗?提前致谢!
更新 1
total_bytes - remaining_bytes
我最近的尝试涉及在连接重置之前跟踪最后一个块的字节位置(即)。Fog 允许您在get
方法的 options 参数中设置自定义标头:
bucket.files.get('file_name.tar.gz', header: {'Range' => "bytes=#{@last_byte}-"}) do |chunk, remaining_bytes, total_bytes|
yielder << chunk
end
因此,当流被重置时,我会尝试使用 HTTP Range 标头从我在新流中中断的地方开始。
但是,Fog 似乎忽略了这个标头,经过一番挖掘,我发现它不是fog-aws
gem 中接受的 HTTP 标头属性:
接下来,我将尝试使用aws-sdk
gem 执行这些相同的步骤,它看起来支持 HTTP Range 标头