Ir al contenido principal
Laravel, shipping fast.

El planificador reemplaza un crontab lleno de entradas por una sola:

* * * * * cd /path/to/app && php artisan schedule:run

Todo lo demás es PHP, en el repositorio, revisado como cualquier otro cambio:

// routes/console.php
Schedule::command('model:prune')->daily();
Schedule::command('sanctum:prune-expired')->daily();
Schedule::command('queue:prune-failed --hours=168')->daily();
Schedule::command('queue:prune-batches')->daily();

Cuatro líneas de mantenimiento, y cada una cumple una promesa que hace otro capítulo: los tokens caducados del Capítulo 4, los jobs fallidos viejos y los lotes terminados del Capítulo 10, y las reglas de retención que el Capítulo 17 pondrá en los modelos. (Documentación de Laravel: Task Scheduling.)

Para ver lo que la aplicación cree que es su programación:

php artisan schedule:list

Eso imprime cada tarea con su expresión y la próxima vez que se ejecutará. Cuando alguien pregunte «¿esa tarea sigue programada?», esta es la respuesta, y no puede estar desactualizada.

Tareas que no deben solaparse ni duplicarse

Una tarea que tarda más que su intervalo empezará otra vez mientras todavía se está ejecutando. En dos servidores, se ejecutará en los dos. Ninguna de las dos cosas es lo que querías. Aquí está otra vez la primera de esas cuatro líneas, protegida:

Schedule::command('model:prune')
    ->daily()
    ->withoutOverlapping()
    ->onOneServer();

withoutOverlapping() se salta una ejecución si la anterior no ha terminado. onOneServer() se asegura de que solo uno de tus servidores la ejecute cada vez. Ambos funcionan mediante un bloqueo en tu caché, lo que significa que la caché tiene que estar compartida entre servidores: Redis o la base de datos, no un archivo en cada máquina. Con un almacén de caché local, onOneServer() no protege nada, y no te lo va a decir.

Que el planificador despache y la cola trabaje

schedule:run ejecuta las tareas pendientes una detrás de otra. Una tarea que tarda diez minutos retrasa todo lo que toca después.

Así que el trabajo del planificador es iniciar el trabajo, no hacerlo:

Schedule::job(new ExportMonthlyUsage)->monthlyOn(1, '03:00');

Eso pone un job en la cola y vuelve al instante. El trabajo tiene entonces todo lo que construyó el Capítulo 10: reintentos, esperas, un método failed() y un lugar en failed_jobs cuando se rinde. Una tarea larga ejecutada en el propio planificador no tiene nada de eso.

Deja en la programación los comandos de mantenimiento cortos e idempotentes. Manda a la cola todo lo pesado.

No se pudo cargar el audio. Inténtalo de nuevo en un momento.