Pregunta ¿Prácticas recomendadas para que la aplicación Rails ejecute una tarea larga en segundo plano?


Tengo una aplicación de Rails que desafortunadamente después de una solicitud a un controlador, tiene que hacer algunos cálculos que toman un tiempo. ¿Cuáles son las mejores prácticas en Rails para proporcionar retroalimentación o progreso en una tarea o solicitud de larga ejecución? Estos métodos de control generalmente duran más de 60 segundos.

No me preocupa el lado del cliente ... Estaba planeando tener una solicitud de Ajax cada segundo y mostrar un indicador de progreso. Simplemente no estoy seguro de las mejores prácticas de Rails, ¿creo un controlador adicional? ¿Hay algo inteligente que pueda hacer? Quiero que las respuestas se centren en el lado del servidor usando solo Rails.

Gracias de antemano por tu ayuda.

Editar:

Si es importante, la solicitud http es para archivos PDF. Luego tengo Rails en conjunto con Ruport generar estos PDF. El problema es que estos archivos PDF son muy grandes y contienen una gran cantidad de datos. ¿Sigue teniendo sentido usar una tarea de fondo? Supongamos que un PDF promedio tarda aproximadamente de un minuto a dos minutos. ¿Esto hará que mi aplicación Rails no responda a cualquier otra solicitud del servidor durante este tiempo?

Editar 2:

De acuerdo, después de una investigación más exhaustiva, parece que mi aplicación Rails no responde a ninguna otra solicitud HTTP después de que una solicitud entra para un PDF grande. Entonces, supongo que la pregunta ahora es: ¿Cuál es el mejor mecanismo de enhebrado / fondo para usar?  Debe ser estable y mantenido. Estoy muy sorprendido de que Rails no tenga algo como esto integrado.

Editar 3:

He leído esta página: http://wiki.rubyonrails.org/rails/pages/HowToRunBackgroundJobsInRails. Me encantaría leer sobre varias experiencias con estas herramientas.

Editar 4:

Estoy usando Passenger Phusion "modrails", si es que importa.

Editar 5:

Estoy usando Windows Vista 64 bit para mi máquina de desarrollo; sin embargo, mi máquina de producción es Ubuntu 8.04 LTS. ¿Debo considerar cambiar a Linux para mi máquina de desarrollo? ¿Las soluciones presentadas funcionarán en ambos?


32


origen


Respuestas:


los Complemento de Workling le permiten programar tareas en segundo plano en una cola (realizarían la tarea larga). A partir de la versión 0.3, puede preguntarle a un trabajador cuál es su estado, esto le permitiría mostrar algunas barras de progreso ingeniosas.

Otra característica interesante de Workling es que el back-end asíncrono se puede cambiar: puedes usar DelayedJobs, Spawn (fork clásico), Starling ...


24



Tengo un sitio de gran volumen que genera muchos archivos CSV grandes. Estos a veces tardan varios minutos en completarse. Yo hago lo siguiente:

  • Tengo una tabla de trabajos con detalles del archivo solicitado. Cuando el usuario solicita un archivo, la solicitud va en esa tabla y lleva al usuario a una página de "estado del trabajo" que enumera todos sus trabajos.
  • Tengo una tarea de rake que ejecuta todos los trabajos pendientes (un método de clase en el modelo de trabajo).
  • Tengo una instalación separada de rieles en otra caja que maneja estos trabajos. Esta casilla solo hace trabajos, y no es accesible al mundo exterior.
  • En este cuadro separado, un trabajo cron ejecuta todos los trabajos pendientes cada 60 segundos, a menos que los trabajos aún se estén ejecutando desde la última invocación.
  • La página de estado del trabajo del usuario se actualiza automáticamente para mostrar el estado del trabajo (que se actualiza en el cuadro de trabajos cuando el trabajo se inicia, se ejecuta y luego finaliza). Una vez que el trabajo está hecho, aparece un enlace al archivo de resultados.

Puede ser demasiado pesado si solo planea ejecutar uno o dos a la vez, pero si quiere escalar ... :)


6



Llamar a ./script/runner en el fondo funcionó mejor para mí. (También estaba haciendo generación de PDF.) Parece el denominador común más bajo, pero también es el más simple de implementar. Aquí hay un resumen de mi experiencia.


4



Una solución simple que no requiere Gemas o complementos adicionales sería crear una tarea de Rake personalizada para manejar la generación de PDF. Puede modelar el proceso de generación de PDF como una máquina de estado con estados tales como presentada, tratamiento y completar que están almacenados en la tabla de la base de datos del modelo. La solicitud HTTP inicial a la aplicación Rails simplemente agregaría un registro a la tabla con un presentada estado y retorno.

Habría un trabajo de cron que ejecuta su tarea de Rake personalizada como un proceso separado de Ruby, por lo que la aplicación principal de Rails no se verá afectada. La tarea Rake puede usar ActiveRecord para encontrar todos los modelos que tienen presentada estado, cambie el estado a tratamiento y luego generar los PDF asociados. Finalmente, debe establecer el estado para completar. Esto permite que sus llamadas AJAX dentro de la aplicación Rails supervisen el estado del proceso de generación de PDF.

Si pones tu tarea de Rake dentro your_rails_app/ lib / tasks luego tiene acceso a los modelos dentro de su aplicación Rails. El esqueleto de tal pdf_generator.rake se vería así:

namespace :pdfgenerator do
  desc 'Generates PDFs etc.'
  task :run => :environment do

    # Code goes here...
  end
end

Como se señala en la wiki, hay algunas desventajas de este enfoque. Utilizarás cron para crear regularmente un proceso Ruby bastante pesado y el tiempo de tus trabajos cron necesitaría una puesta a punto cuidadosa para asegurarte de que cada uno tenga tiempo suficiente para completar antes de que aparezca el siguiente. Sin embargo, el enfoque es simple y debe satisfacer sus necesidades.


2



Esto parece un hilo bastante viejo. Sin embargo, lo que tengo abajo en mi aplicación, que requiere ejecutar múltiples Temporizadores de cuenta atrás para diferentes páginas, fue para usar Ruby Thread. El temporizador debe continuar ejecutándose incluso si la página fue cerrada por los usuarios.
 
  Ruby hace que sea fácil escribir programas de subprocesos múltiples con la clase Thread. Los hilos Ruby son una forma ligera y eficiente de lograr el paralelismo en tu código. Espero que esto ayude a otros vagabundos que buscan alcanzar el trasfondo: paralelismo / servicios concurrentes en su aplicación. Del mismo modo, Ajax hace que sea mucho más fácil invocar una acción Rails [custom] específica cada segundo.


2



Esto realmente suena como algo que debería tener un proceso en segundo plano en lugar de una instancia de aplicación (pasajero / mestizo), de esa manera su aplicación puede seguir haciendo lo que se supone que debe hacer, atendiendo solicitudes, mientras que una tarea de fondo de algún tipo, Workling es bueno, maneja el número de crujidos. Sé que esto no trata el tema del progreso, pero a menos que sea absolutamente esencial, creo que es un precio pequeño a pagar.

Puede hacer que un usuario haga clic en la acción requerida, hacer que esa acción pase la solicitud a la cola de Workling y que le envíe algún tipo de notificación al usuario cuando se complete, tal vez un correo electrónico o algo así. No estoy seguro de lo práctico de eso, solo de pensar en voz alta, pero mi punto es que realmente parece que debería ser una tarea de fondo de algún tipo.


1



Estoy usando Windows Vista 64 bit para mi   máquina de desarrollo; sin embargo, mi   La máquina de producción es Ubuntu 8.04 LTS.   ¿Debo considerar cambiar a Linux   para mi máquina de desarrollo? Será el   ¿Las soluciones presentadas funcionan en ambos?

¿Has considerado ejecutar Linux en una máquina virtual sobre Vista?


1



Recomiendo usar Resque joya con es estado de resque complemento para tus procesos de fondo pesados.

Resque

Resque es una biblioteca Ruby respaldada por Redis para crear trabajos en segundo plano,   colocándolos en múltiples colas, y procesarlos más tarde.

Estado de Resque

resque-status es una extensión del sistema de cola de resque proporciona   trabajos rastreados simples.

Una vez que ejecute un trabajo en un trabajador de Resque utilizando la extensión resque-status, podrá obtener información sobre sus progresos en curso y la capacidad de matar un proceso específico muy fácilmente. Ver ejemplos:

status.pct_complete #=> 0
status.status #=> 'queued'
status.queued? #=> true
status.working? #=> false
status.time #=> Time object        
status.message #=> "Created at ..."

También resque-y resque-status tiene una interfaz web genial para interactuar con sus trabajos, que es genial.


1