Ejecutar action en segundo plano

Tengo un formulario donde selecciono una planilla excel y la subo, y luego de esto ejecuto otro método que parsea los datos y los importa a la base de datos. El tema es que demora media hora el proceso, (y obviamente media hora de espera con el navegador) y necesito ejecutarlo en segundo plano. Alguien sabe cómo puedo hacerlo?

Estuve probando los componentes runaction y backjob, y el primero me arroja un error y el otro si bien funciona, de igual forma tengo que esperar que el método import() termine para poder pasar al redirect.

Tengo esto:


public function actionIndex(){

  $form = new FormularioArchivo;

	

  if(isset($_POST['FormularioArchivo'])){

    $form->attributes = $_POST['FormularioArchivo'];

    $form->archivo = CUploadedFile::getInstance($form,'archivo');


    if($form->validate()){

	$form->archivo->saveAs('csv/csv.csv');

	$this->import(); // ESTE ES EL METODO QUE LEE Y PARSEA EL ARCHIVO

        $this->redirect(array('gracias'));

    }

  }

}

Cualquier ayuda se agradece.

Saludos. :blink:

Un servidor web no está pensado para mantener abierta una conexión media hora, o haces el proceso mas eficiente, o vas a tener que cambiar el enfoque…

Tienes acceso a la shell de tu servidor para ejecutar comandos?

podrías hacer el proceso con una aplicación de consola funcionan muy bien, yo tengo varias aplicaciones de consola que se ejecutan periódicamente gracias a Cron (linux).

Desde una aplicación de consola tienes acceso a todos los models de tu aplicación web, BD y varias cosas más, podrías ejecutarla periódicamente, comprobar si hay trabajos pendientes, y si los hay procesarlos.

Ten en cuenta varias cosas:

  • Se te pueden acumular varios archivos pendientes de procesar, y no vas a tener acceso a las variables $_POST, (porque no hay ningún POST, esto es una llamada directa a PHP).

  • Cron ejecuta los comandos con el usuario root del servidor a menos que le digas lo contrario.

  • (de esto no estoy seguro, pero creo que) Cron no sabe si el comando anterior ha terminado o no, así que ten cuidado de no procesar el mismo paquete varias veces a la vez.

  • Tendrás que guardar en algún sitio el estado de cada tarea, el resultado, etc… de forma que desde la aplicación web se pueda ver.

De todas formas, estoy echando un ojo a backjob y tiene muy buena pinta… Yo no te puedo ayudar porque no lo he usado nunca, pero internamente debe crear una petición http a localhost. La última vez que intenté algo parecido no conseguí mas que problemas, pero fue hace años, y esto de backjob parece bastante logrado.

A ver si alguien que lo haya usado puede decirte algo.

Se me ocurre que puede estarte fallando, porque dentro del action que se ejecuta en background, no tienes acceso al fichero. yo intentaría guardar el fichero en una carpeta temporal, y pasarle la ruta al background job

Un saludo.

Hola Cristobal!

Yo soy bastante nuevo aqui (con Yii en gral, no así con PHP y otros frameworks), pero llevo algunos dias armando algo con BackJob y me funciona bastante bien.

Para usar BackJob deberias modificar tu codigo. Imagino que mas o menos de la siguiente forma:

  1. Lo que estas haciendo dentro del if



    $form->attributes = $_POST['FormularioArchivo'];

    $form->archivo = CUploadedFile::getInstance($form,'archivo');


    if($form->validate()){

        $form->archivo->saveAs('csv/csv.csv');

        $this->import(); // ESTE ES EL METODO QUE LEE Y PARSEA EL ARCHIVO

        $this->redirect(array('gracias'));

    }



deberia pasar a una nueva action, que va a ser la que se ejecute en segundo plano (a modo de ejemplo la llamare: procesarUpload). Deberias quitarle el redirect, e incluir llamadas a Yii::app()->background->update(n) para poder informar el progreso de la tarea.

  1. Entonces dentro del if, lo que te va a quedar es la llamada de backJob para disparar la tarea en segundo plano , junto con el redirect:



 if(isset($_POST['FormularioArchivo'])){

    Yii::app()->background->start(array('miController/procesarUpload'));

    $this->redirect(array('gracias'));

 }



  1. Luego, en la pagina a la que redirijas, le podrás indicar al usuario que la tarea está en proceso y de alguna forma ir mostrandole el progreso.

Estoy omitiendo un millon de detalles (por ejemplo, faltaría pasarle los datos del POST al procesarUpload), pero intento darte una idea.

Si necesitas mas ayuda me podes contactar.

Saludos,

Gastón