2012-08-28 3 views
4

CSV를 통해 매우 많은 양의 데이터를 다운로드 할 수있는 기능을 사용자에게 제공하고 있습니다. 이렇게하기 위해 Sidekiq을 사용하고 일단 작업을 시작하면 백그라운드 작업을 시작합니다. 백그라운드 작업에서 수행 한 작업은 적절한 데이터가 모두 포함 된 CSV를 생성하고 /tmp에 저장 한 다음 저장을 호출합니다! 내 모델에서 파일 위치를 paperclip 속성으로 전달하고 그 속성은 S3에서 저장됩니다.CSV를 생성하여 백그라운드 작업 완료시 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 

내가 readabilities 술에 대한 쿼리 방법을 생략했습니다.

답변

1

여기 Heroku의 임시 파일 저장소가 문제가 아닌 것 같습니다. 그 주변의 경고는 주로 a) dynos가 일회성이라는 사실을 중심으로하므로 작성한 모든 내용은 예고없이 사라질 수 있습니다. b) dynos는 서로 바꿔 쓸 수 있기 때문에 두 개 이상의 웹 dyno를 실행하는 경우 요청 간 임시 파일의 존재는 운이 좋을 때가 있습니다. 그러나 어떠한 상황에서도 작업자가 실행되는 동안 임시 파일이 사라집니다. (대신 쓰기 위해 여는)

> 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이 비어 있고 이미 덮어 쓰여진 파일 열기 파일 핸들을 제공 할 때 Paperclip이하는 일을 파고 들지는 못했지만 그 흐름을 변경하면 문제가 잘 해결 될 수 있습니다.

대신에 다음과 같이 메모리에서이 작업을 수행 할 수 있습니다. CSV를 문자열로 생성하고이를 PaperIO에 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으로 암시 적으로 변환하지 않습니다. 레일즈 3.2 – xamenrax