Cómo crear un cronjob en Magento2

Cronjobs en Magento2

Ya que estábamos con la consola, vamos a aprovechar para armar nuestro primer cronjob (de juguete) en Magento2.

Para no perder la sana costumbre, vamos a comenzar por definir nuestro cronjob a través de un xml dentro de etc (en nuestro módulo).

/etc/crontab.xml

Y el contenido podría ser:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="default">
        <job name="sampleModuleCron" instance="Barbanet\SampleModule\Cron\Sample" method="execute">
            <schedule>* * * * *</schedule>
        </job>
    </group>
</config>

¿Qué significa todo eso?

  • group_name: nombre del grupo al cual pertenece el cronjob (más adelante veremos las implicancias de esto). Este valor no tiene por qué ser único.
  • job_name: el identificador único de la tarea.
  • classpath: la clase que se va a instanciar.
  • method: el método de la clase que se va a ejecutar.
  • schedule: es la expresión cron del momento en el cual será ejecutada la tarea (aunque sobre este tema, también volveremos más adelante).

Ya he creado mi definición del cronjob, así que en base a esos valores ingresados ahora debo crear mi clase.

<?php
 
namespace Barbanet\SampleModule\Cron;
 
class Sample
{
 
    public function execute()
    {
        /* Do things!  */
    }
}

Un detalle aquí es que, de la misma forma que en Magento 1, los cronjobs son clases que no heredan de ninguna otra. Quizás lo único diferente aquí es que no necesariamente han de estar dentro de la carpeta de Models.

En la documentación no he encontrado nada específico, y algunos ejemplos, algunos usan el directorio Cron, otros prefieren Jobs. En mi caso, la decisión ha ido por Cron (para mi TOC tiene más sentido).

Ahora que tengo todo preparado, puedo probar el cronjob haciendo uso de la consola con el comando:

bin/magento cron:run

Si ahora reviso en base de datos, en la tabla cron_schedule, veré que mi cronjob fue ejecutado:

Cronjob ejecutado en Magento2

Bien, esto ha sido lo muy muy básico, pero veamos cómo hacer un par de cosas extra.

Grupos

Podemos definir grupos de cronjobs, e incluso, podemos ejecutarlos de forma aislada (a los grupos).

Por defecto, tenemos los grupos «default» e «index». Esto podemos verlo claramente en la configuración.

Configuración cronjobs en Magento2

Ahora, en nuestor xml habíamos indicado:

<group id="default">

Aquí bien podríamos indicar otro grupo o, si queremos, podemos crear nuestro propio grupo. La idea detrás de los grupos es poder armar pools de cronjobs y evitar el bloqueo o listas interminables de ejecución.

Supongamos que quisíeramos crear un nuevo grupo de cronjobs que usáramos para integrar con nuestro ERP.

Creamos entonces, dentro de nuestro módulo, el archivo etc/cron_groups.xml, y, a los fines de mi ejemplo, con este contenido:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/cron_groups.xsd">
    <group id="sample_module_group">
        <schedule_generate_every>1</schedule_generate_every>
        <schedule_ahead_for>4</schedule_ahead_for>
        <schedule_lifetime>2</schedule_lifetime>
        <history_cleanup_every>10</history_cleanup_every>
        <history_success_lifetime>60</history_success_lifetime>
        <history_failure_lifetime>600</history_failure_lifetime>
        <use_separate_process>1</use_separate_process>
    </group>
</config>

Ahora editamos nuestro crontab.xml y le indicamos el mismo grupo que acabamos de crear.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="sample_module_group">
        <job name="sampleModuleCron" instance="Barbanet\SampleModule\Cron\Sample" method="execute">
            <schedule>* * * * *</schedule>
        </job>
    </group>
</config>

Si ahora revisamos las configuraciones, veremos que nuestro grupo está separado y con configuraciones de ejecución propia.

Configuración cronjobs en Magento2

Si ahora quiero ejecutar sólo las tareas de mi grupo, puedo probar usando la consola con el siguiente comando:

bin/magento cron:run --group="sample_module_group"

Esto ejecutará sólo los cronjobs de ese cron group.

Configuración de ejecución

En lugar de configurar nuestro cronjob desde el XML, vamos a hacerlo de forma gráfica desde el backend (caso contrario, ante algún cambio de configuración habría que deployar, regenerar cache, etc, etc, etc).

Entonces, en el archivo crontab.xml cambiamos la línea:

<schedule>* * * * *</schedule>

Por:

<config_path>samplemodule/cron/schedule</config_path>

Luego, volvemos a nuestro archivo /etc/adminhtml/system.xml y agregamos un campo al final de la sección para configuración del cronjob.

<group id="cron" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
    <label>Cron configuration</label>
    <field id="schedule" translate="label comment" type="text" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
        <label>Schedule</label>
        <comment><![CDATA[
<code>
* * * * *
| | | | |
| | | | +---- Day of the Week   (range: 1-7, 1 standing for Monday)
| | | +------ Month of the Year (range: 1-12)
| | +-------- Day of the Month  (range: 1-31)
| +---------- Hour              (range: 0-23)
+------------ Minute            (range: 0-59)
Example: 0 0 * * * Daily at midnight
</code>
        ]]></comment>
    </field>
</group>

Esto nos dejaría la configuración de nuestro módulo de la siguiente manera:

Configuración cronjobs en Magento2
Configuración cronjobs en Magento2

Ahora, configuramos el momento de ejecución y luego volvemos a probar nuestro cronjob (usemos la consola nuevamente).

El resultado debería ser el de la ejecución exitosa del cronjob (según lo que hayamos configurado para nuestro cronjob).

El código resultante de este ejemplo se encuentra en el branch 2.10.0 del módulo Barbanet_SampleModule.