2011-08-08 12 views
5

Acabo de empezar a usar resque para hacer algunos procesamientos en algunos archivos muy grandes en segundo plano, y tengo problemas para descifrar cómo pasar un archivo a un trabajador resque. Utilizo los raíles para manejar la carga del archivo, y los raíles crean un objeto ActionDispatch::Http::UploadedFile por cada archivo cargado desde el formulario.Enviando el archivo cargado al trabajador resque para ser procesado

¿Cómo se envía este archivo a un empleado de resque? Intenté enviar un hash personalizado con solo la ruta del archivo temporal y el nombre original, pero no puedo volver a abrir el archivo temporal en el trabajador resque (solo un Errno::ENOENT - No such file or directory normal) porque los rieles parecen eliminar ese archivo temporal una vez que finaliza la solicitud .

Respuesta

5

Http::UploadedFile no se puede acceder una vez que finaliza la solicitud. Necesita escribir el archivo en algún lugar (o usar s3 como almacenamiento temporal). Pase resque la ruta al archivo que escribió.

+0

Parece la única manera. Simplemente no quería manejar el movimiento del archivo antes del procesamiento y la eliminación posterior. Gracias. –

5

Acabo de pasar dos días tratando de hacer esto y finalmente lo descubrí. Es necesario que Base64 codifique el archivo para que se pueda serializar en json. Luego hay que decodificar en el trabajador y crear un nuevo

ActionDispatch::Http::UploadedFile

es cómo codificar y transmitir a resque aquí:

// 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) 

y aquí es cómo decodificar y convertir de nuevo a un objeto dentro de su trabajador

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

No recomendaría hacer esto, a menos que esté seguro de que sus archivos nunca serán superiores a unos cientos de KB. Escribir el archivo en disco/s3/etc y pasar esa ruta al trabajo de Resque es la forma correcta de manejar esto. – pnomolos

+0

Definitivamente de acuerdo con @pnomolos que esto no es bueno para archivos de gran tamaño, pero es un truco ingenioso si se trata de archivos pequeños (por ejemplo, CSV de 5-10 KB) en los que no vale la pena cargarlos en S3 y luego -descargándolos cuando los necesite. – ACIDSTEALTH

Cuestiones relacionadas