2012-08-28 24 views
4

我向用户提供了通过CSV下载大量数据的功能。为此,我使用Sidekiq,并在任务启动后将任务关闭到后台任务中。我在后台作业中所做的是生成包含所有正确数据的csv,并将其存储在/tmp中,然后调用save!在我的模型上,将文件的位置传递给回形针属性,然后关闭并存储在S3中。在完成后台作业时生成CSV并将其上传到S3

所有这一切在本地工作完美。我现在的问题在于Heroku,它能够根据你所在的节点存储短时间的文件。由于Heroku如何处理这些文件,我的后台作业无法找到保存的tmp文件。我想我正在寻找更好的方法来做到这一点。如果有某种方式可以在内存中完成所有的事情,那就太棒了。唯一的问题是回形针需要一个实际的文件对象作为保存模型时的一个属性。下面是我的后台作业的样子:

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 

我省略了readabilities着想的查询方法。

回答

1

我不认为Heroku的临时文件存储是这里的问题。这些警告主要围绕以下事实:a)dynos是短暂的,所以你写的任何东西都可以在没有通知的情况下消失;和b)dynos是可以互换的,所以当你有多个web dyno在运行时,请求间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 =线只设置文件名(而不是打开它写),然后让update_report打开文件名进行阅读。当你给它一个空的,已经被覆盖的,打开的可写文件句柄时,我还没有深入到Paperclip做什么,但改变这个流程可能会很好地解决这个问题。

或者,您也可以在内存中执行此操作:将CSV生成为字符串并将其作为StringIO提供给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 
+0

很棒!我实际上最终以StringIO方式进行。 – John

+0

我有TypeError:没有将CSV隐式转换为String的方法,rails 3.2 – xamenrax

相关问题