El archivo de configuración clásico para las entradas de trabajos cron en el sistema operativo Linux es el siguiente:
Los primeros cinco parámetros indican el tiempo de ejecuciĂłn de esta tarea, y el sexto, el comando en sĂ, que debe ejecutarse. Los parámetros de tiempo son: minutos, horas, dĂas, meses y dĂa de la semana. Además, todos los nĂşmeros deben representarse como enteros o en forma de sintaxis especial .Como resultado, el intervalo mĂnimo posible para iniciar un comando es una vez por minuto.Para muchas tareas, la ejecuciĂłn de comandos se necesita con mucha más frecuencia, por ejemplo, cada 10 segundos. Para algunas tareas de automatizaciĂłn de procesos de negocio, el retraso máximo permitido a menudo no es más de 1-1.5 segundos.Por supuesto, el cron clásico no es adecuado para esto: debe mejorarse.La siguiente es una implementaciĂłn paso a paso de crear funcionalidades adicionales (en PHP) para el cron clásico en Linux usando protecciĂłn adicional contra reiniciar procesos.ConfiguraciĂłn de tareas y configuraciĂłn cron
Por ejemplo, utilizaremos la siguiente tarea:- En la parte frontal, el usuario puede iniciar la ejecuciĂłn de una tarea compleja haciendo clic en el botĂłn "Ejecutar";
- El back end despuĂ©s de escribir una nueva lĂnea en la base de datos informa al usuario de la confirmaciĂłn;
- A través de cron, "rastrearemos" esas nuevas tareas y las completaremos lo más rápido posible para que el usuario no obtenga el resultado en un minuto, sino de inmediato *.
* Si usa el lanzamiento de comandos, solo por minuto, la tarea comenzará cuando los segundos lleguen al cero más cercano (el comienzo de un nuevo minuto). Por lo tanto, en la forma clásica, el usuario deberá esperar la ejecución de 0 a 59 segundos.Entonces, cron se configurará en su forma máxima, es decir una vez por minuto* * * * * /usr/bin/php -q /run.php > /dev/null 2>&1
Ciclo Ăşnico
Inicialmente, debe decidir con qué frecuencia solicitaremos nuevas tareas en la base de datos, dependiendo de esto, el número de ciclos y la suspensión lógica (función sleep
) cambiarán.En el ejemplo actual, se utiliza un paso de 10 segundos. Por lo tanto, el número de ciclos es 60/10 = 6. Total, el código general es el siguiente:for ($cycle = 1; $cycle <= 6; $cycle++) {
$all_tasks = get_all_tasks();
if ($all_tasks) {
foreach($all_tasks as $one_task) {
solve_one_task($one_task);
}
}
sleep(10);
}
AclaraciĂłn : en este ejemplo, se utiliza un paso de 10 segundos, que puede proporcionar un intervalo mĂnimo de ejecuciĂłn del script una vez cada 10 segundos. En consecuencia, para una ejecuciĂłn más frecuente, debe cambiar el nĂşmero de ciclos y el "tiempo de suspensiĂłn".Evitar la ejecuciĂłn repetida de tareas
En la forma presentada, hay una incertidumbre, a saber, la ejecuciĂłn repetida de la tarea si ya se ha iniciado. Esto se vuelve especialmente cierto si la tarea es "difĂcil" y requiere unos segundos para implementarla.Esto crea un problema de re-ejecuciĂłn:- La funciĂłn
solve_one_task()
ya se está ejecutando, pero aĂşn no ha completado su trabajo; - Por lo tanto, en la base de datos la tarea todavĂa está marcada como no cumplida;
- El siguiente ciclo obtendrá esta tarea nuevamente y ejecutará la función
solve_one_task()
nuevamente, con la misma tarea.
Por supuesto, esto se puede resolver, por ejemplo, cambiando algún estado en la base de datos para esta tarea.Pero no cargaremos la base de datos: según mis pruebas, MYSQL puede aceptar la solicitud, pero no procesarla de inmediato. Una diferencia de incluso 0,5 segundos puede conducir a la ejecución repetida, lo que categóricamente no es adecuado.También en este caso solo estamos hablando del estado de las tareas, por lo que es mejor usar el sistema de archivos del servidor.El modelo de verificación básico se construye usando flock
una funciĂłn que establece y desbloquea un archivo.En la ejecuciĂłn de PHP, la funciĂłn se puede representar de la siguiente manera:$lock_file_abs = 'file';
$fp = fopen($lock_file_abs,"w+");
if (flock($fp, LOCK_EX | LOCK_NB)) {
solve_one_task($one_task);
flock($fp, LOCK_UN);
}
else {
}
fclose($fp);
unlink($lock_file_abs);
Resultado
La visiĂłn general de todo el ciclo es la siguiente:for ($cycle = 1; $cycle <= 6; $cycle++) {
$all_tasks = get_all_tasks();
if ($all_tasks) {
foreach($all_tasks as $one_task) {
$lock_file_abs = __DIR__.'/locks/run_'.$one_task['id'];
$fp = fopen($lock_file_abs,"w+");
if (flock($fp, LOCK_EX | LOCK_NB)) {
solve_one_task($one_task);
flock($fp, LOCK_UN);
}
else {
}
fclose($fp);
unlink($lock_file_abs);
}
}
sleep(10);
}
Por lo tanto, dicho algoritmo le permite iniciar una ejecuciĂłn cĂclica del procesamiento de tareas y no le preocupa que la tarea se procese más de una vez.Y ahora es suficiente simplemente ejecutar este cĂłdigo a travĂ©s de cron cada minuto, y, a su vez, ejecutará ciclos más pequeños ya dentro de sĂ mismo.