2012-08-28 27 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

相關問題