Cómo ejecutar un trabajo PHP varias veces en un minuto con Crontab en Ubuntu 20.04

Índice
  1. Introducción
  • Prerrequisitos
  • Paso 1: Configuración de una base de datos
  • Paso 2: Creación de un script PHP que ejecute tareas después de 5 segundos
  • Paso 3: Programar la ejecución del script PHP después de 1 minuto
  • Paso 4: Confirmación de la ejecución del trabajo
  • Conclusión
  • La autora seleccionó a Girls Who Code para recibir una donación como parte del programa Write for DOnations .

    Introducción

    En Linux, puedes usar la versátil herramienta crontab para procesar tareas de larga duración en segundo plano en momentos específicos. Si bien el demonio es excelente para ejecutar tareas repetitivas, tiene una limitación: solo puedes ejecutar tareas en un intervalo de tiempo mínimo de 1 minuto.

    Sin embargo, en muchas aplicaciones, para evitar una mala experiencia del usuario, es preferible que los trabajos se ejecuten con mayor frecuencia. Por ejemplo, si utiliza el modelo de cola de trabajos para programar tareas de procesamiento de archivos en su sitio web, una espera significativa tendrá un impacto negativo en los usuarios finales.

    Otro escenario es una aplicación que utiliza el modelo de cola de trabajos para enviar mensajes de texto o correos electrónicos a los clientes una vez que han completado una determinada tarea en una aplicación (por ejemplo, enviar dinero a un destinatario). Si los usuarios tienen que esperar un minuto antes de recibir un mensaje de confirmación, podrían pensar que la transacción falló e intentar repetirla.

    Para superar estos desafíos, puede programar un script PHP que ejecute bucles y procese tareas de forma repetitiva durante 60 segundos mientras espera que el demonio crontab lo vuelva a llamar después de un minuto. Una vez que el demonio crontab llama al script PHP por primera vez, puede ejecutar tareas en un período de tiempo que coincida con la lógica de su aplicación sin hacer esperar al usuario.

    En esta guía, creará una cron_jobsbase de datos de muestra en un servidor Ubuntu 20.04. Luego, configurará una taskstabla y un script que ejecute los trabajos en su tabla en intervalos de 5 segundos utilizando el while(...){...}bucle y sleep()las funciones de PHP.

    Prerrequisitos

    Para completar este tutorial, necesitará lo siguiente:

    • Un servidor Ubuntu 20.04 configurado con un usuario que no sea root. Siga nuestra guía de configuración inicial del servidor con Ubuntu 20.04 .

    • Una pila LAMP configurada en su servidor. Consulte la guía Cómo instalar la pila Linux, Apache, MySQL, PHP (LAMP) en Ubuntu 20.04 . Para este tutorial, puede omitir el Paso 4: Creación de un host virtual para su sitio web .

    Paso 1: Configuración de una base de datos

    En este paso, creará una base de datos y una tabla de muestra. Primero, SSHacceda a su servidor e inicie sesión en MySQL como raíz:

    1. sudo mysql -u root -p

    Ingrese su contraseña raíz para el servidor MySQL y presione ENTERcontinuar. Luego, ejecute el siguiente comando para crear una cron_jobsbase de datos.

    1. CREATE DATABASE cron_jobs;

    Cree un usuario que no sea root para la base de datos. Necesitará las credenciales de este usuario para conectarse a la cron_jobsbase de datos desde PHP. Recuerde reemplazar EXAMPLE_PASSWORDpor un valor seguro:

    1. CREATE USER 'cron_jobs_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'EXAMPLE_PASSWORD';
    2. GRANT ALL PRIVILEGES ON cron_jobs.* TO 'cron_jobs_user'@'localhost';
    3. FLUSH PRIVILEGES;

    A continuación, cambie a la cron_jobsbase de datos:

    1. USE cron_jobs;
    OutputDatabase changed

    Una vez que haya seleccionado la base de datos, cree una taskstabla. En esta tabla, insertará algunas tareas que se ejecutarán automáticamente mediante un trabajo cron. Dado que el intervalo de tiempo mínimo para ejecutar un trabajo cron es de 1un minuto, más adelante codificará un script PHP que anule esta configuración y, en su lugar, ejecute los trabajos en intervalos de 5 segundos.

    Por ahora, crea tu taskstabla:

    1. CREATE TABLE tasks (
    2. task_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    3. task_name VARCHAR(50),
    4. queued_at DATETIME,
    5. completed_at DATETIME,
    6. is_processed CHAR(1)
    7. ) ENGINE = InnoDB;

    NOW()Inserte tres registros en la tabla de tareas. Utilice la función MySQL en la queued_atcolumna para registrar la fecha y hora actuales en las que se ponen en cola las tareas. Además, para la completed_atcolumna, utilice la CURDATE()función MySQL para establecer una hora predeterminada de 00:00:00. Más adelante, a medida que se completen las tareas, su secuencia de comandos actualizará esta columna:

    1. INSERT INTO tasks (task_name, queued_at, completed_at, is_processed) VALUES ('TASK 1', NOW(), CURDATE(), 'N');
    2. INSERT INTO tasks (task_name, queued_at, completed_at, is_processed) VALUES ('TASK 2', NOW(), CURDATE(), 'N');
    3. INSERT INTO tasks (task_name, queued_at, completed_at, is_processed) VALUES ('TASK 3', NOW(), CURDATE(), 'N');

    Confirme la salida después de ejecutar cada INSERTcomando:

    OutputQuery OK, 1 row affected (0.00 sec)...

    Asegúrese de que los datos estén en su lugar ejecutando una SELECTdeclaración en la taskstabla:

    1. SELECT task_id, task_name, queued_at, completed_at, is_processed FROM tasks;

    Encontrará una lista de todas las tareas:

    Output+---------+-----------+---------------------+---------------------+--------------+| task_id | task_name | queued_at           | completed_at        | is_processed |+---------+-----------+---------------------+---------------------+--------------+|       1 | TASK 1    | 2021-03-06 06:27:19 | 2021-03-06 00:00:00 | N            ||       2 | TASK 2    | 2021-03-06 06:27:28 | 2021-03-06 00:00:00 | N            ||       3 | TASK 3    | 2021-03-06 06:27:36 | 2021-03-06 00:00:00 | N            |+---------+-----------+---------------------+---------------------+--------------+3 rows in set (0.00 sec)

    El tiempo de la completed_atcolumna se establece en 00:00:00, esta columna se actualizará una vez que las tareas sean procesadas por un script PHP que creará a continuación.

    Salir de la interfaz de línea de comandos de MySQL:

    1. QUIT;
    OutputBye

    Su cron_jobsbase de datos y taskstabla ahora están en su lugar y ahora puede crear un script PHP que procese los trabajos.

    Paso 2: Creación de un script PHP que ejecute tareas después de 5 segundos

    En este paso, creará un script que utiliza una combinación del while(...){...}bucle PHP y sleepfunciones para ejecutar tareas cada 5 segundos.

    Abra un nuevo /var/www/html/tasks.phparchivo en el directorio raíz de su servidor web usando nano:

    1. sudo nano /var/www/html/tasks.php

    A continuación, crea un nuevo try {bloque después de una ?phpetiqueta y declara las variables de base de datos que creaste en el Paso 1. Recuerda reemplazarlas EXAMPLE_PASSWORDcon la contraseña real de tu usuario de base de datos:

    /var/www/html/tareas.php

    ?phptry {    $db_name     = 'cron_jobs';    $db_user     = 'cron_jobs_user';    $db_password = 'EXAMPLE_PASSWORD';    $db_host     = 'localhost';

    A continuación, declara una nueva clase PDO (objeto de datos PHP) y establece el atributo ERRMODE_EXCEPTIONpara detectar cualquier error de PDO. Además, cambia ATTR_EMULATE_PREPARESa falsepara permitir que el motor de base de datos MySQL nativo se encargue de la emulación. Las declaraciones preparadas te permiten enviar las consultas SQL y los datos por separado para mejorar la seguridad y reducir las posibilidades de un ataque de inyección SQL:

    /var/www/html/tareas.php

        $pdo = new PDO('mysql:host=' . $db_host . '; dbname=' . $db_name, $db_user, $db_password);    $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);      $pdo-setAttribute(PDO::ATTR_EMULATE_PREPARES, false);       

    Luego, crea una nueva variable llamada $loop_expiry_timey configúrala con la hora actual más 60 segundos. Luego, abre una nueva while(time() $loop_expiry_time) {declaración PHP. La idea aquí es crear un bucle que se ejecute hasta que la hora actual ( time()) coincida con la variable $loop_expiry_time:

    [label /var/www/html/tasks.php]           $loop_expiry_time = time() + 60;    while (time()  $loop_expiry_time) { 

    A continuación, declare una declaración SQL preparada que recupere trabajos no procesados ​​de la taskstabla:

    [label /var/www/html/tasks.php]           $data = [];        $sql  = "select                  task_id                 from tasks                 where is_processed = :is_processed                 ";

    Ejecute el comando SQL y obtenga todas las filas de la taskstabla que tengan la columna is_processedestablecida en N. Esto significa que las filas no se procesan:

    [label /var/www/html/tasks.php]          $data['is_processed'] = 'N';          $stmt = $pdo-prepare($sql);        $stmt-execute($data);

    A continuación, recorra las filas recuperadas mediante una while ($row = $stmt-fetch(PDO::FETCH_ASSOC)) {...}sentencia PHP y cree otra sentencia SQL. Esta vez, el comando SQL actualiza las columnas is_processedy completed_atpara cada tarea procesada. Esto garantiza que no procese las tareas más de una vez:

    [label /var/www/html/tasks.php]          while ($row = $stmt-fetch(PDO::FETCH_ASSOC)) {             $data_update   = [];                     $sql_update    = "update tasks set                               is_processed  = :is_processed,                              completed_at  = :completed_at                              where task_id = :task_id                                                               ";            $data_update   = [                                       'is_processed' = 'Y',                                                       'completed_at' = date("Y-m-d H:i:s"),                             'task_id'      = $row['task_id']                                                      ];            $stmt = $pdo-prepare($sql_update);            $stmt-execute($data_update);        }

    Nota: Si tiene una cola grande para procesar (por ejemplo, 100 000 registros por segundo), puede considerar poner en cola los trabajos en un servidor Redis, ya que es más rápido que MySQL cuando se trata de implementar el modelo de cola de trabajos. Sin embargo, esta guía procesará un conjunto de datos más pequeño.

    Antes de cerrar la primera while (time() $loop_expiry_time) {declaración PHP, incluya una sleep(5);declaración para pausar la ejecución de los trabajos durante 5 segundos y liberar recursos del servidor.

    Puede cambiar el período de 5 segundos según la lógica de su empresa y la velocidad con la que desea que se ejecuten las tareas. Por ejemplo, si desea que las tareas se procesen 3 veces en un minuto, configure este valor en 20 segundos.

    Recuerde catchcualquier mensaje de error PDO dentro de un } catch (PDOException $ex) { echo $ex-getMessage(); }bloque:

    [label /var/www/html/tasks.php]                 sleep(5);         }       } catch (PDOException $ex) {    echo $ex-getMessage(); }

    Su tasks.phpexpediente completo quedará como sigue:

    /var/www/html/tareas.php

    ?phptry {    $db_name     = 'cron_jobs';    $db_user     = 'cron_jobs_user';    $db_password = 'EXAMPLE_PASSWORD';    $db_host     = 'localhost';    $pdo = new PDO('mysql:host=' . $db_host . '; dbname=' . $db_name, $db_user, $db_password);    $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);      $pdo-setAttribute(PDO::ATTR_EMULATE_PREPARES, false);                   $loop_expiry_time = time() + 60;    while (time()  $loop_expiry_time) {         $data = [];        $sql  = "select                  task_id                 from tasks                 where is_processed = :is_processed                 ";        $data['is_processed'] = 'N';                     $stmt = $pdo-prepare($sql);        $stmt-execute($data);        while ($row = $stmt-fetch(PDO::FETCH_ASSOC)) {             $data_update   = [];                     $sql_update    = "update tasks set                               is_processed  = :is_processed,                              completed_at  = :completed_at                              where task_id = :task_id                                                               ";            $data_update   = [                                       'is_processed' = 'Y',                                                       'completed_at' = date("Y-m-d H:i:s"),                             'task_id'      = $row['task_id']                                                      ];            $stmt = $pdo-prepare($sql_update);            $stmt-execute($data_update);        }                  sleep(5);         }       } catch (PDOException $ex) {    echo $ex-getMessage(); }

    Guarde el archivo presionando CTRL+ X, Yluego ENTER.

    Una vez que haya terminado de codificar la lógica en el /var/www/html/tasks.phparchivo, programará el demonio crontab para que ejecute el archivo cada 1 minuto en el siguiente paso.

    Paso 3: Programar la ejecución del script PHP después de 1 minuto

    En Linux, puedes programar trabajos para que se ejecuten automáticamente después de un tiempo estipulado ingresando un comando en el archivo crontab. En este paso, le indicarás al demonio crontab que ejecute tu /var/www/html/tasks.phpscript después de cada minuto. Por lo tanto, abre el /etc/crontabarchivo usando nano:

    1. sudo nano /etc/crontab

    Luego agregue lo siguiente hacia el final del archivo para ejecutarlo http://localhost/tasks.phpdespués de cada 1minuto:

    /etc/crontab

    ...* * * * * root /usr/bin/wget -O - http://localhost/tasks.php

    Guarde y cierre el archivo.

    Esta guía asume que tienes conocimientos básicos sobre cómo funcionan los trabajos cron. Considera leer nuestra guía sobre Cómo usar Cron para automatizar tareas en Ubuntu .

    Como se indicó anteriormente, aunque el demonio cron ejecuta el tasks.phparchivo cada 1 minuto, una vez que el archivo se ejecuta por primera vez, repetirá las tareas abiertas durante otros 60 segundos. Cuando expire el tiempo del bucle, el demonio cron ejecutará el archivo nuevamente y el proceso continuará.

    Después de actualizar y cerrar el /etc/crontabarchivo, el demonio crontab debería comenzar a ejecutar las tareas MySQL que insertó en la taskstabla de inmediato. Para confirmar si todo está funcionando como se espera, consultará su cron_jobsbase de datos a continuación.

    Paso 4: Confirmación de la ejecución del trabajo

    En este paso, abrirá su base de datos una vez más para verificar si el tasks.phparchivo está procesando trabajos en cola cuando lo ejecuta automáticamente crontab.

    Vuelva a iniciar sesión en su servidor MySQL como root:

    1. sudo mysql -u root -p

    Luego, ingrese la contraseña raíz de su servidor MySQL y presione ENTERpara continuar. Luego, cambie a la base de datos:

    1. USE cron_jobs;
    OutputDatabase changed

    Ejecute una SELECTdeclaración contra la tasks tabla:

    SELECT task_id, task_name, queued_at, completed_at, is_processed FROM tasks;

    Recibirá un resultado similar al siguiente. En la completed_atcolumna, las tareas se han procesado a intervalos de 5segundos. Además, las tareas se han marcado como completadas, ya que la is_processedcolumna ahora está configurada en Y, lo que significa YES.

    Output+---------+-----------+---------------------+---------------------+--------------+| task_id | task_name | queued_at           | completed_at        | is_processed |+---------+-----------+---------------------+---------------------+--------------+|       1 | TASK 1    | 2021-03-06 06:27:19 | 2021-03-06 06:30:01 | Y            ||       2 | TASK 2    | 2021-03-06 06:27:28 | 2021-03-06 06:30:06 | Y            ||       3 | TASK 3    | 2021-03-06 06:27:36 | 2021-03-06 06:30:11 | Y            |+---------+-----------+---------------------+---------------------+--------------+3 rows in set (0.00 sec)

    Esto confirma que su script PHP está funcionando como se esperaba; ha ejecutado tareas en un intervalo de tiempo más corto anulando la limitación del período de tiempo de 1 minuto establecido por el demonio crontab.

    Conclusión

    En esta guía, ha configurado una base de datos de muestra en un servidor Ubuntu 20.04. Luego, ha creado trabajos en una tabla y los ha ejecutado en intervalos de 5 segundos mediante el while(...){...}bucle y sleep()las funciones de PHP. Utilice la lógica de este tutorial la próxima vez que implemente una aplicación basada en cola de trabajos en la que las tareas deban ejecutarse varias veces en un período de tiempo de 1 minuto.

    Para obtener más tutoriales de PHP, consulte nuestra página de temas de PHP .

    SUSCRÍBETE A NUESTRO BOLETÍN 
    No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    Subir

    Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion