【问题标题】:Heroku: Unpacking a Gzip file through a rake task failsHeroku:通过 rake 任务解压 Gzip 文件失败
【发布时间】:2018-11-23 01:11:40
【问题描述】:

我将 Rails 5.2ruby 2.5.1 一起使用,并将我的应用程序部署到 Heroku

我在尝试运行本地 rake 任务时遇到了问题。该任务调用一个以*.gz 文件响应的API,将其保存、压缩,然后使用检索到的JSON 填充数据库,最后删除*.gz 文件。该任务在开发中运行顺利,但在生产中调用时。打印到控制台的最后一行是“Unzipping the file...”,所以我猜测问题来自 zlib 库。

companies_list.rake

require 'json'
require 'open-uri'
require 'zlib'
require 'openssl'
require 'action_view'

include ActionView::Helpers::DateHelper

desc 'Updates Company table'
task update_db: :environment do
  start = Time.now
  zip_file_url = 'https://example.com/api/download'

  TEMP_FILE_NAME = 'companies.gz'

  puts 'Creating folders...'

  tempdir = Dir.mktmpdir
  file_path = "#{tempdir}/#{TEMP_FILE_NAME}"

  puts 'Downloading the file...'

  open(file_path, 'wb') do |file|
    open(zip_file_url, { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }) do |uri|
      file.write(uri.read)
    end
  end

  puts 'Download complete.'
  puts 'Unzipping the file...'

  gz = Zlib::GzipReader.new(open(file_path))
  output = gz.read
  @companies_array = JSON.parse(output)

  puts 'Unzipping complete.'

  (...)
end

有没有其他人遇到过类似的问题并且知道如何让它工作?

【问题讨论】:

  • 没有在 heroku 中使用 zlib。您可以尝试运行系统命令gunzip -l file.gz。如果文件已正确下载且未损坏,您应该会看到文件内容。从控制台尝试一下。
  • 我刚刚运行 heroku -logs 并意识到问题出在其他地方:API 返回的文件超出了我们的 Heroku 配额(错误 R15(内存配额严重超出)...
  • 每个响应都带有一个 gz 文件,不同吗?如果没有,您应该考虑缓存这些请求。您还可以将大量消耗内存的操作卸载到其他服务 (AWS)。 Heroku 可以为您的应用提供服务。
  • 这是一个包含来自官方注册表的公司数据的 API,因此我们的想法是每晚运行脚本以获取更新(如果有的话) - 所以是的,理论上响应可能会有所不同.我们正在研究使用 JSON 流媒体(目前没有多大成功)。

标签: ruby-on-rails ruby heroku rake zlib


【解决方案1】:

问题与内存限制有关,而不是 Gzip 解包(这就是问题仅在生产中出现的原因)。

解决方案是使用Json::Streamer,这样整个文件就不会立即加载到内存中。

这是关键部分:(在问题中发布的代码之后)

  puts 'Updating the Company table...'
  streamer = Json::Streamer.parser(file_io: file, chunk_size: 1024)  # customize your chunk_size
  streamer.get(nesting_level: 1) do |company|
    (do your stuff with the API data here...)
  end
end

【讨论】:

    【解决方案2】:

    您的代码 sn-p 并不表示您曾经关闭过 GzipReader。通常最好将 IO 包装在块中,以确保它们被适当地关闭。此外,open 方法可能不是您想要的方法,因此只需让 GzipReader 为您处理打开文件并发送file_path

    Zlib::GzipReader.new(file_path) do |gz|
      output = gz.read
      @companies_array = JSON.parse(output)
    end
    

    【讨论】:

    • 我使用this SO 来解压我的gzip 文件,如上所述,脚本在本地运行。似乎我的问题与内存使用有关(这取决于您的 Heroku 计划),所以我正在尝试研究 JSOM 流以希望找到解决方法。
    猜你喜欢
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    相关资源
    最近更新 更多