加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – 在后台作业完成后生成CSV并将其上传到S3

发布时间:2020-12-17 02:02:33 所属栏目:百科 来源:网络整理
导读:我正在为用户提供通过CSV下载大量数据的功能.要做到这一点,我正在使用Sidekiq,并在启动它后将任务放入后台工作.我在后台工作中所做的是生成一个包含所有正确数据的csv,将其存储在/ tmp中然后调用save!在我的模型上,将文件的位置传递给paperclip属性,然后该
我正在为用户提供通过CSV下载大量数据的功能.要做到这一点,我正在使用Sidekiq,并在启动它后将任务放入后台工作.我在后台工作中所做的是生成一个包含所有正确数据的csv,将其存储在/ tmp中然后调用save!在我的模型上,将文件的位置传递给paperclip属性,然后该属性将关闭并存储在S3中.

所有这一切在当地完美地运作.我现在的问题在于Heroku,它能够根据您所在的节点短时间存储文件.由于Heroku如何处理这些文件,我的后台作业无法找到保存的tmp文件.我想我正在寻找一种更好的方法来做到这一点.如果有一些方法可以在内存中完成所有事情,那将是非常棒的.唯一的问题是,当您保存模型时,paperclip需要将实际文件对象作为属性.这是我的后台工作的样子:

class CsvWorker
  include Sidekiq::Worker

  def perform(report_id)
    puts "Starting the jobz!"
    report = Report.find(report_id)
    items = query_ranged_downloads(report.start_date,report.end_date)

    csv = compile_csv(items)

    update_report(report.id,csv)
  end

  def update_report(report_id,csv)
    report = Report.find(report_id)
    report.update_attributes(csv: csv,status: true)
    report.save!
  end

  def compile_csv(items)
    clean_items = items.compact
    path = File.new("#{Rails.root}/tmp/uploads/downloads_by_title_#{Process.pid}.csv","w")
    csv_string = CSV.open(path,"w") do |csv|
      csv << ["Item Name","Parent","Download Count"]
      clean_items.each do |row|
        if !row.item.nil? && !row.item.parent.nil?
        csv << [
          row.item.name,row.item.parent.name,row.download_count
          ]
        end
      end
    end

    return path
  end
end

为了便于阅读,我省略了查询方法.

解决方法

我不认为Heroku的临时文件存储是这里的问题.围绕这一点的警告主要集中在这样的事实:a)dynos是短暂的,所以你写的任何东西都可以在没有通知的情况下消失;和b)dynos是可以互换的,因此当你有多个web dyno运行时,inter-request tempfiles的存在是一个好运.但是,在您的工作人员运行时,临时文件在任何情况下都不会消失.

我注意到的一件事是你实际上正在创建两个具有相同名称的临时文件:

> path = File.new("/tmp/filename","w")
 => #<File:/tmp/filename> 
> path.fileno
 => 3 
> CSV.open(path,"w") do |csv| csv << %w(foo bar baz); puts csv.fileno end
4
 => nil

你可以改变path = line来设置文件名(而不是打开它来写),然后让update_report打开文件名进行读取.当你给它一个空的,已经被覆盖的,打开写入的文件句柄时,我还没有深入研究Paperclip所做的事情,但改变这个流程可能很好地解决了这个问题.

或者,您可以在内存中执行此操作:将CSV生成为字符串并将其作为StringIO提供给Paperclip. (Paperclip支持某些非文件对象,包括StringIO,使用例如Paperclip::StringioAdapter.)尝试类似:

# returns a CSV as a string
def compile_csv(items)
  CSV.generate do |csv|
     # ...
  end
end

def update_report(report_id,csv)
  report = Report.find(report_id)
  report.update_attributes(csv: StringIO.new(csv),status: true)
  report.save!
end

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读