jueves, 14 de noviembre de 2013

Ejecutar tareas programadas en Symfony 2 usando comandos Symfony y Cron

A veces, durante el desarrollo de una aplicación, necesitamos que se ejecute algún tipo de acción cada cierto periodo de tiempo. Por ejemplo podemos querer enviar un correo electrónico a cada usuario que lleve más de 3 días sin hacer login en la aplicación con un resumen de las notificaciones que tiene pendientes de leer con el fin de incitarle a seguir usando la aplicación. Otro ejemplo del uso de las tareas programadas podría ser una aplicación en la que el usuario crea eventos y los gestiona. Sería interesante que cuando un evento finaliza (tiene una fecha/hora de finalización) se envíe un correo a su creador con un resumen de cómo ha ido el evento: asistentes, recaudación, etc. Para llevar esto a cabo tenemos que hacer uso de los comandos Symfony por una parte y por otra del administrador de tareas programadas de Unix (Cron).

En primer lugar necesitamos crear el comando symfony que ejecute la funcionalidad que deseamos. Para ello creamos una carpeta llamada Command en nuestro Bundle (al mismo nivel que Controller o Resources) y le pondremos nombre a nuestra clase. El nombre siempre tiene que terminar en Command o no funcionará. Le vamos a llamar MyCommand.

Como podéis ver la clase extiende de ContainerAwareCommand y tiene dos métodos: configure y execute. Extendemos de ContainerAwareCommand ya que de esta manera tenemos acceso al Service Container simplemente haciendo $this->getContainer(). Esto nos servirá para acceder a servicios muy comunes como el Entity Manager o el Mailer.

En cuanto a los métodos en configure definimos el nombre del comando, en nuestro caso devness:my_command (luego explicaré para qué sirve) Como podéis observar en el ejemplo he incluido un argumento llamado "my_argument" de tipo opcional. Si usamos la constante InputArgument::REQUIRED en lugar de InputArgument::OPTIONAL el argumento será obligatorio.

En el método execute es donde llevamos a cabo la tarea. En el código podéis ver algunas cosas típicas que pueden hacerse. Si se tratase del ejemplo que he dado en la introducción sobre enviar un correo-resumen de notificaciones a los usuarios que llevan días sin entrar aquí sería donde accederíamos a la base de datos para averiguar qué usuarios reunen los requisitos para recibir dicho correo y nos encargaríamos de enviarlo. Ahora que ya tenemos nuestro comando nos vamos al directorio donde tenemos nuestro proyecto symfony y lo ejecutamos:

  • php app/console devness:mycommand --my_argument=valor

Como en nuestro ejemplo el argumento es opcional podríamos omitirlo:
  • php app/console devness:mycommand

Funciona? Perfecto. Ahora necesitamos que esta tarea se ejecute en algún momento determinado del tiempo, normalmente de manera periódica. Para ello usaremos Cron (En sistemas UNIX como Linux o Mac OS X). En este post no pretendo explicar como funciona Cron, ya que con usar un poco a nuestro amigo Google podemos descubrir como funciona. En resumidas cuentas tenemos un archivo de texto llamado crontab que podemos editar en el servidor donde corre la aplicación Symfony mediante el siguiente comando:
  • crontab -e

En mi ordenador este comando me abre el crontab con el editor Vim. Yo prefiero nano, por lo que yo lo ejecuto así:
  • EDITOR=nano crontab -e

Si queremos que nuestra tarea se ejecute cada minuto escribiríamos la siguiente línea en nuestro crontab
  • * * * * * php /Ruta/Absoluta/Hasta/Proyecto/Symfony/app/console devness:mycommand --myargument=valor

Si quisiéramos que se ejecutase cada 2 horas escribiríamos esto:
  • * */2 * * * php /Ruta/Absoluta/Hasta/Proyecto/Symfony/app/console devness:mycommand --myargument=valor

Y ya está! ya tenemos nuestro comando Symfony ejecutándose temporalmente como nosotros queríamos. Podéis encontrar más ejemplos y información sobre el formato del crontab haciendo click aquí


4 comentarios:

  1. Ya hice el comando y funciona bien, el lio es que estoy trabajndo en windows y no tengoidea como hacer que el comando se ejecute en un momento determinado.

    ResponderEliminar
    Respuestas
    1. facil lo puedes realizar con las tareas programadas de windows

      Eliminar
    2. Existe algún planificador (portable de ser posible) que permita ejecutarlas sin necesidad de configurar nada fuera de la app? De manera que con algunos pasos preconfigurados durante el despliegue, se pueda correr inmediatamente, sólo una vez quedaría registrado el planificador y ahí en lo adelante las tareas.
      Gracias

      Eliminar
  2. Este comentario ha sido eliminado por el autor.

    ResponderEliminar