Как я могу предотвратить удаление Tempfile, созданного Creek, до того, как я закончу с ним? - PullRequest
1 голос
/ 20 сентября 2019

Я пишу сценарий Creek и файл .xlsx и использую его для обновления цен и веса продуктов в базе данных.Файл .xlsx находится на сервере AWS, поэтому Creek копирует файл и сохраняет его в Tempfile во время его использования.

Проблема заключается в том, что в какой-то момент кажется, что Tempfile преждевременно удален,и поскольку Creek продолжает вызывать его всякий раз, когда он перебирает лист, сценарий завершается ошибкой.Интересно, что в среде моего коллеги сценарий работает нормально, хотя я не нашел разницы между тем, что мы запускаем.

Вот сценарий, который я написал:

require 'creek'

class PricingUpdateWorker
  include Sidekiq::Worker

  def perform(filename)
    # This points to the file in the root bucket
    file = bucket.files.get(filename)

    # Make public temporarily to open in Creek
    file.public = true
    file.save

    creek_sheets = Creek::Book.new(file.public_url, remote: true).sheets

    # Close file to public
    file.public = false
    file.save

    creek_sheets.each_with_index do |sheet, sheet_index|
      p "---------- #{sheet.name} ----------"

      sheet.simple_rows.each_with_index do |row, index|
        next if index == 0

        product = Product.find_by_id(row['A'].to_i)
        if product
          if row['D']&.match(/N\/A/) || row['E']&.match(/N\/A/)
            product.delete
            p '*** deleted ***'
          else
            product.price = row['D']&.to_f&.round(2)
            product.weight = row['E']&.to_f
            product.request_for_quote = false
            product.save
            p 'product updated'
          end
        else
          p "#{row['A']} | product not found ***"
        end
      end
    end
  end

  private

  def connection
    @connection ||= Fog::Storage.new(
      provider: 'AWS',
      aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
      aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
    )
  end

  def bucket
    # Grab the file from the bucket
    @bucket ||= connection.directories.get 'my-aws-bucket'
  end
end

Ижурналы:

"---------- Sheet 1 ----------"
"product updated"
"product updated"
... I've cut out a bunch more of these...
"product updated"
"product updated"
"---------- Sheet 2 ----------"
rails aborted!
Errno::ENOENT: No such file or directory @ rb_sysopen - /var/folders/9m/mfcnhxmn1bqbm6h91rx_rd8m0000gn/T/file20190920-19247-c6x4zw

"/ var / folder / 9m / mfcnhxmn1bqbm6h91rx_rd8m0000gn / T / file20190920-19247-c6x4zw" - это временный файл, и, как вы можете видеть, он уже собран, хотя я 'Я все еще использую это, и я верю, что это все еще в области.Есть идеи, что может быть причиной этого?Это особенно странно, что мой коллега может выполнить это очень хорошо.

В случае, если это полезно, вот небольшой код из Creek:

def initialize path, options = {}
      check_file_extension = options.fetch(:check_file_extension, true)
      if check_file_extension
        extension = File.extname(options[:original_filename] || path).downcase
        raise 'Not a valid file format.' unless (['.xlsx', '.xlsm'].include? extension)
      end
      if options[:remote]
        zipfile = Tempfile.new("file")
        zipfile.binmode
        zipfile.write(HTTP.get(path).to_s)
        # I added the line below this one, and it fixes the problem by preventing the file from being marked for garbage collection, though I shouldn't need to take steps like that.
        # ObjectSpace.undefine_finalizer(zipfile)
        zipfile.close
        path = zipfile.path
      end
      @files = Zip::File.open(path)
      @shared_strings = SharedStrings.new(self)
    end

РЕДАКТИРОВАТЬ: Кто-то хотел точно знать, как я былзапускаю свой код, вот он.

Я запускаю следующую задачу rake, выполняя bundle exec rails client:pricing_update[client_updated_prices.xlsx] в командной строке.

namespace :client do
  desc 'Imports the initial database structure & base data from uploaded .xlsx file'
  task :pricing_update, [:filename] => :environment do |t, args|
    PricingUpdateWorker.new.perform(args[:filename])
  end
end

Я должен также упомянуть, что я использую RailsТаким образом, Gemfile.lock поддерживает версии gem между мной и моим коллегой.Моя версия тумана 2.0.0 и моя версия rubyzip 1.2.2.

1 Ответ

0 голосов
/ 21 сентября 2019

Наконец, похоже, что ошибка вовсе не в геме Creek, а скорее в геме rubyzip, имеющем проблемы с файлами xlsx, как отмечено в эта проблема Кажется, это зависит от того, как источник файла былгенерироваться.Я создал простую двухстраничную электронную таблицу в листах Google, и она отлично работает, но случайный файл xlsx может и не работать.

require 'creek'

def test_creek(url)
  Creek::Book.new(url, remote: true).sheets.each_with_index do |sheet, index|
    p "----------Name: #{sheet.name} Index: #{index} ----------"
    sheet.simple_rows.each_with_index do |row, i|
        puts "#{row} index: #{i}"
    end
  end
end

test_creek 'https://tc-sandbox.s3.amazonaws.com/creek-test.xlsx'
# works fine should output
"----------Name: Sheet1 Index: 0 ----------"
{"A"=>"foo ", "B"=>"sheet", "C"=>"one"} index: 0
"----------Name: Sheet2 Index: 1 ----------"
{"A"=>"bar", "B"=>"sheet", "C"=>"2.0"} index: 0

test_creek 'http://dev-builds.libreoffice.org/tmp/test.xlsx'
# raises error
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...