2011-08-08 28 views
5

Właśnie zacząłem używać resque do przetwarzania niektórych bardzo dużych plików w tle i mam problem z ustaleniem, jak przekazać plik do pracownika resque. Używam szyn do obsługi przesyłania plików, a szyny tworzą obiekt ActionDispatch::Http::UploadedFile dla każdego pliku przesłanego z formularza.Wysyłanie przesłanego pliku, aby ponownie dodać pracownika do przetworzenia.

Jak wysłać ten plik do pracownika resque? Próbowałem wysłać niestandardowy skrót nazwy ścieżki pliku tymczasowego i oryginalnej nazwy pliku, ale nie mogę ponownie otworzyć pliku tymczasowego w module do odświeżania (po prostu normalnym Errno::ENOENT - No such file or directory), ponieważ wydaje się, że szyny usuwają ten plik tymczasowy po zakończeniu żądania .

Odpowiedz

5

Http::UploadedFile jest niedostępny po zakończeniu żądania. Musisz gdzieś zapisać plik (lub użyć s3 jako pamięci tymczasowej). Prześlij ponownie nazwę ścieżki do pliku, który napisałeś.

+0

Wydaje się, że jest to jedyny sposób. Po prostu nie chciałem poradzić sobie z przenoszeniem pliku przed jego przetworzeniem i późniejszym usunięciem. Dzięki. –

5

Po prostu spędziłem dwa dni próbując to zrobić i wreszcie to rozgryzłem. Musisz zakodować plik Base64, aby mógł zostać zserializowany do json. Następnie trzeba dekodować go w pracownika i utworzyć nowy

ActionDispatch::Http::UploadedFile

Oto jak zakodować i przekazać do Resque:

// You only need to encode the actual file, everything else in the 
// ActionDispatch::Http::UploadedFile object is just string or a hash of strings 

file = params[:file] // Your ActionDispatch::Http::UploadedFile object 
file.tempfile.binmode 
file.tempfile = Base64.encode64(file.tempfile.read) 

Resque.enqueue(QueueWorker, params) 

A oto jak do dekodowania i konwersji z powrotem do obiektu w ciągu Twój pracownik

class QueueWorker 
    @queue = :main_queue 

    def self.perform(params) 
     file = params['file'] 
     tempfile = Tempfile.new('file') 
     tempfile.binmode 
     tempfile.write(Base64.decode64(file['tempfile'])) 

     // Now that the file is decoded you need to build a new 
     // ActionDispatch::Http::UploadedFile with the decoded tempfile and the other 
     // attritubes you passed in. 

     file = ActionDispatch::Http::UploadedFile.new(tempfile: tempfile, filename: file['original_filename'], type: file['content_type'], head: file['headers']) 

     // This object is now the same as the one in your controller in params[:file] 
    end 
end 
+3

Nie polecałbym tego, chyba że masz pewność, że twoje pliki nigdy nie będą większe niż kilkaset KB. Zapisywanie pliku na dysku/s3/etc i przekazywanie tej ścieżki do zadania Resque jest właściwym sposobem na obsłużenie tego. – pnomolos

+0

Zdecydowanie zgadzam się z @pnomolosem, że nie jest to dobre dla dużych plików, ale jest to sprytny hack, jeśli masz do czynienia z małymi plikami (np. 5-10 KB CSV), w których nie jest to warte kłopotów z przesłaniem ich do S3, a następnie ponownego - pobieranie ich, gdy ich potrzebujesz. – ACIDSTEALTH

Powiązane problemy