2009-05-12 8 views
5

Estoy trabajando en una aplicación Django que permite a un usuario cargar archivos. Necesito realizar algún procesamiento del lado del servidor en estos archivos antes de enviarlos al Amazon S3. Después de leer las respuestas a this question y this blog post decidí que la mejor manera de manejar esto es hacer que mi controlador de vista invoque un método en el objeto remoto Pyro para realizar el proceso de forma asincrónica y luego devolver inmediatamente una Http 200 al cliente. Tengo este prototipo y parece funcionar bien, sin embargo, también me gustaría almacenar el estado del procesamiento para que el cliente pueda sondear la aplicación para ver si el archivo se ha procesado y cargado en S3.¿Cómo debo almacenar el estado de un proceso de larga ejecución invocado desde Django?

Puedo manejar el sondeo con la suficiente facilidad, pero no estoy seguro de dónde está la ubicación adecuada para almacenar el estado del proceso. Tiene que ser editable por el proceso Pyro y legible por mi vista de votación.

  • Tengo dudas en agregar columnas a la base de datos para datos que realmente solo deberían durar de 30 a 60 segundos.
  • He considerado utilizar low-level cache API de Django y usar una identificación de archivo como la clave, sin embargo, no creo que esto sea realmente para lo que está diseñado el marco de caché y no estoy seguro de qué problemas imprevistos podría haber con ir este ruta.
  • Por último, he considerado almacenar estado en el objeto Pyro que realiza el procesamiento, pero aún parece que necesitaría agregar una columna de base de datos "processing_complete" booleana para que la vista sepa si consultar o no estado desde el Pyro objeto.

Por supuesto, también hay algunos problemas de integridad de datos con desacoplamiento de estado de la base de datos (lo que ocurre si el servidor se cae y todos estos datos es en memoria?). Voy a escuchar cómo los desarrolladores de aplicaciones web más experimentados podrían manejar este tipo de procesamiento con estado.

Respuesta

6

Hacemos esto teniendo una tabla de "Solicitud" en la base de datos.

Cuando llega la carga, creamos el objeto Archivo cargado y creamos una Solicitud.

Comenzamos el procesador por lotes de fondo.

Devolvemos una página de 200 "estamos trabajando en ello": muestra las Solicitudes y su estado.

Nuestro procesador de lotes utiliza el ORM de Django. Cuando termina, actualiza el objeto Request. Podemos (pero no lo hacemos) enviar una notificación por correo electrónico. Principalmente, solo actualizamos el estado para que el usuario pueda iniciar sesión de nuevo y ver que el procesamiento se haya completado.


Batch Server Notas de arquitectura.

Es un servidor WSGI que espera en un puerto una solicitud de procesamiento por lotes. La solicitud es un POST DESCANSO con un número de identificación; el procesador por lotes lo busca en la base de datos y lo procesa.

El servidor se inicia automágicamente mediante nuestra interfaz REST. Si no se está ejecutando, lo engendramos. Esto hace que la transacción del usuario parezca lenta, pero, bueno. Se supone que no se cuelga.

Además, tenemos un crontab simple para comprobar que se está ejecutando. Como máximo, estará abajo durante 30 minutos entre "¿estás vivo?" cheques.No tenemos un script de inicio formal (corremos bajo Apache con mod_wsgi), pero podemos crear un script de "reinicio" que toque el archivo WSGI y luego haga una POST a una URL que haga un chequeo de estado (y comience el procesador por lotes).

Cuando se inicia el servidor por lotes, puede haber solicitudes no procesadas para las que nunca se ha obtenido un POST. Por lo tanto, el inicio predeterminado es sacar TODO el trabajo de la cola de solicitud, suponiendo que se haya perdido algo.

+0

Después de pensar en esto de la noche a la mañana, he decidido que tienes toda la razón. Simplemente no tiene sentido no usar la base de datos. También he decidido que Pyro no encaja bien aquí y que debería hacer lo que hace la gente normal y usar un trabajo cron con un archivo de bloqueo. – bouvard

+0

No usamos cron. Tenemos nuestro sistema por lotes como un pequeño servidor WSGI y hacemos una solicitud HTTP con urllib2 para reactivarlo. Obtiene el ID de solicitud de la solicitud de WSGI; obtiene los detalles con ordinario Django ORM. –

+0

Esto es algo así como lo que planeé hacer con Pyro, pero el problema que preveo es que una interrupción repentina del servidor podría dejar los documentos medio procesados ​​y no habría un nuevo mensaje de solicitud para reiniciar el procesamiento. Si utilizo un trabajo cron, sé que puedo simplemente elegir los 10 trabajos sin terminar de la tabla de Solicitud y retiraré los que hayan sido cortados durante la interrupción. – bouvard

1

Entonces, es una cola de trabajos lo que necesita. Para su caso, definitivamente iría con el DB para guardar el estado, incluso si esos estados son de corta duración. Parece que cumplirá todos sus requisitos, y no es terriblemente difícil de implementar ya que tiene todas las piezas móviles disponibles para usted. Mantenlo simple a menos que necesite algo más complejo.

Si necesita algo más potente o más sofisticado, me gustaría ver algo así como Gearman.

5

Sé que esta es una pregunta antigua, pero a alguien le puede resultar útil incluso después de todo este tiempo, así que aquí va.

Por supuesto, puede utilizar la base de datos como cola, pero existen soluciones desarrolladas exactamente para ese fin.

AMQP está hecho exclusivamente para eso. Junto con Celery o Carrot y un servidor intermediario como RabbitMQ o ZeroMQ.

Eso es lo que estamos utilizando en nuestro último proyecto y está funcionando muy bien.

Para su problema, Celery and RabbitMQ parece ser la opción más adecuada. RabbitMQ proporciona persistencia de sus mensajes, y Celery expone las vistas fáciles para el sondeo para verificar el estado de los procesos que se ejecutan en paralelo.

Quizás te interese octopy.

Cuestiones relacionadas