Solución de problemas · Laravel
¿El scheduler de Laravel no se ejecuta? Soluciona el fallo silencioso
Por qué el scheduler de Laravel para silenciosamente — la entrada cron ausente, usuario incorrecto, entorno y tareas solapadas — y cómo solucionarlo.
El scheduler de Laravel funciona gracias a una única entrada cron del sistema. Si esa entrada es incorrecta — o el entorno bajo ella lo es — todas las tareas programadas dejan de funcionar silenciosamente. Aquí está la lista de comprobación.
1. La entrada cron debe existir
Laravel necesita exactamente una línea en crontab que llame a schedule:run cada
minuto. Confirma que está para el usuario correcto (normalmente tu usuario de
despliegue, no root):
crontab -l
Debe verse así:
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
Si falta, añádela con crontab -e. Un error habitual en el despliegue es añadirla
como root mientras la app corre como www-data (o al revés).
2. Usa el binario PHP correcto y la ruta absoluta
Bajo cron, php puede no resolverse, o puede ser la versión incorrecta. Usa la
ruta completa y la ruta del proyecto:
* * * * * cd /var/www/app && /usr/bin/php8.3 artisan schedule:run >> /dev/null 2>&1
3. El entorno es diferente al de tu shell
Cron no carga tu perfil de shell, así que todo lo que hayas definido allí no
estará disponible. Laravel lee .env, lo cual está bien — pero si tus tareas
llaman a otros binarios, dales un PATH explícito. Asegúrate también de que
APP_ENV y la configuración de cola y caché coincidan con producción.
4. Silenciaste la salida y ahora no puedes depurar
>> /dev/null 2>&1 oculta todo, incluidos los errores. Regístralo temporalmente:
* * * * * cd /var/www/app && php artisan schedule:run >> storage/logs/schedule.log 2>&1
Luego ejecuta php artisan schedule:run a mano y lee la salida — la mayoría de
los fallos (permisos, variables de entorno ausentes, conexión a BD) aparecen
de inmediato.
5. Las tareas se solapan o se cuelgan
Una tarea larga que se ejecuta cada minuto puede acumularse. Usa los guards de Laravel para que una ejecución lenta no bloquee la siguiente:
$schedule->command('reports:build')
->hourly()
->withoutOverlapping()
->onOneServer();
El problema más profundo: el scheduler puede parar y quedarse callado
Si schedule:run deja de dispararse — el servidor se reinició, el crontab se
borró en el despliegue, se actualizó PHP — Laravel no tiene forma de avisarte.
Tus informes y correos en cola simplemente se detienen.
Haz ping a un heartbeat desde una tarea programada para saber que el scheduler en sí está vivo:
$schedule->call(function () {
Http::timeout(10)->get('https://ping.steadycron.com/<tu-ping-token>');
})->everyFifteenMinutes();
Si ese ping desaparece, SteadyCron te alerta — el scheduler está caído, antes de que tus usuarios lo noten.