Mostrando entradas con la etiqueta cron. Mostrar todas las entradas
Mostrando entradas con la etiqueta cron. Mostrar todas las entradas

jueves, 14 de noviembre de 2013

Scheduled tasks in Symfony2: Symfony commands and Cron

Sometimes we need some tasks to be executed regularly. We could, for instance, want to send every midnight an email to every user who hasn't logged into our app for three days in order to provide him with a report of unseen notifications.  To get jobs like this done in a Symfony app we need two tools: Symfony commands and a task scheduler such as Cron in UNIX systems.

First of all we need to create a Symfony command which will execute the required functionality. We will create a folder named Command inside our Bundle (It will be on the same level as Controller or Resources folders). Then we create the command class, whose name must end with "Command". In this case I'll name it MyCommand.



As you can see MyCommand class extends ContainerAwareCommand class so that we can use the Service Container just by doing $this->getContainer(). This will give us access to any registered service, such as Doctrine Entity Manager or SwiftMailer.

As far as class methods are concerned, we have two methods: configure and execute. In configure method we will configure our command. We give it a name, in this case devness:my_command and arguments if necessary. Arguments can be required or optional, depending on the second argument of addArgument method (InputArgument::OPTIONAL or InputArgument::REQUIRED)

Execute is the method in charge of doing the hard work. As mentioned before we can get any service through the service container. Inside this method we could, for example, check for users who hadn't logged in for some time using Doctrine and then send them an e-mail. Now we have our Symfony command, so we will run it.

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

  • Our argument is optional so we could omit it:
    • php app/console devness:mycommand

    Does it work? Perfect. Now we need this task to be run at some point in time, or regularly (every five minutes, every day, etc.). We will use Cron to schedule this task. You only will be able to go ahead on this tutorial if you run your Symfony app in a UNIX environment such as Linux or Mac OS X. It's not the purpose of this post to give a master class about Cron (I'm including a good reference at the end of the post). In short, we have a plain text file named crontab which we can edit by executing the following command:
    • crontab -e
    In my laptop this command opens the file using Vim. I don't really like Vim much (to be honest I don't even understand it, I should give it a try) so I execute it this way (nano editor):
    • EDITOR=nano crontab -e

    If we want our Symfony command to be run every minute we will ad the following line to the crontab:
    • * * * * * php /Path/to/SymfonyApp/app/console devness:mycommand --myargument=value

    Or If we wanted to execute it every two hours we could add this instead:
    • * */2 * * * php /Path/to/SymfonyApp/app/console devness:mycommand --myargument=value

    So that's it! We already have our Symfony command up and running. You can get some additional info on crontab format following this link

    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í