Laravel Scheduler es una de las herramientas más elegantes del framework.
Permite definir tareas programadas desde código, sin depender de múltiples cron jobs desordenados.
El problema es que muchos proyectos:
Lo configuran mal
No lo monitorean
Asumen que “siempre corre”
Descubren el fallo semanas después
En producción, el Scheduler no es opcional, es parte crítica de la infraestructura.
Este artículo explica cómo usar Laravel Scheduler correctamente en producción, no solo cómo definir tareas.
¿Qué es realmente Laravel Scheduler?
Laravel Scheduler no reemplaza cron.
Lo que hace es:
Centralizar todas las tareas programadas en
app/Console/Kernel.phpEjecutarlas a través de un solo cron del sistema
Cron → Laravel → Scheduler → Tareas
Configuración mínima correcta en producción
1. Un solo cron job del sistema
En el servidor (Linux):
* * * * * php /ruta/a/tu/proyecto/artisan schedule:run >> /dev/null 2>&1
Este cron:
Se ejecuta cada minuto
Laravel decide qué sí y qué no ejecutar
⚠️ Error común: crear múltiples cron jobs por tarea.
Definición de tareas en Laravel
En
app/Console/Kernel.php:protected function schedule(Schedule $schedule) { $schedule->command('reports:daily') ->dailyAt('01:00') ->withoutOverlapping() ->onOneServer(); }
Esto no ejecuta nada por sí solo si el cron no está activo.
Problemas reales del Scheduler en producción
1. El cron no está corriendo
Causas comunes:
Servidor mal configurado
Deploy nuevo sin cron
Cambio de ruta del proyecto
PHP incorrecto en cron
Solución:
Verifica manualmente:
php artisan schedule:run
2. Tareas ejecutándose dos veces
Muy común en:
Múltiples servidores
Load balancers
Kubernetes / autoscaling
Solución obligatoria:
->onOneServer()
Esto requiere:
Cache centralizado (Redis recomendado)
3. Tareas solapadas
Ejemplo:
Tarea cada minuto
Dura 3 minutos
Resultado:
3 ejecuciones simultáneas
Datos corruptos
Solución:
->withoutOverlapping()
Laravel usa locks de cache para evitarlo.
Scheduler + Jobs: la combinación correcta
❌ Error común:
Meter toda la lógica pesada en el Scheduler
✅ Enfoque correcto:
Scheduler dispara Jobs
Jobs hacen el trabajo pesado
$schedule->job(new ProcessMonthlyReport) ->monthlyOn(1, '02:00');
Ventajas:
Reintentos
Timeouts
Mejor manejo de errores
Escalabilidad
Manejo de errores en tareas programadas
Por defecto:
Si una tarea falla, nadie se entera
Soluciones reales:
Logs explícitos
$schedule->command('sync:data') ->daily() ->sendOutputTo(storage_path('logs/sync.log'));
Notificaciones en fallo
$schedule->command('billing:close') ->daily() ->onFailure(function () { // Slack, email, webhook });
Scheduler y ETL / procesos batch
En producción:
El Scheduler inicia
El Job controla
Ejemplo típico:
Scheduler diario
Job ETL
Manejo de errores por registro
Estados del proceso (
,RUNNING
, etc.)FAILED
Nunca pongas ETL pesado directamente en el Scheduler.
Timezones: error silencioso clásico
Laravel Scheduler usa el timezone de la app:
config('app.timezone')
Error típico:
Servidor en UTC
Negocio en horario local
Tareas ejecutándose “a destiempo”
Solución:
Define el timezone correcto
Documenta horarios críticos
Monitoreo del Scheduler
Buenas prácticas mínimas:
Logs dedicados
Registro en base de datos
Alertas si no corre
Ejemplo:
Registrar última ejecución exitosa
Comparar contra
now()Alertar si se pasó el tiempo esperado
Checklist real para Scheduler en producción
Antes de decir “ya quedó”:
Cron activo en servidor
Ruta correcta a
artisanPHP correcto en cron
en tareas críticasonOneServer()
en procesos largoswithoutOverlapping()Logs visibles
Jobs para lógica pesada
Alertas ante fallos
Relación con la serie completa
Este artículo conecta con los anteriores:
Idempotencia → Scheduler puede ejecutar más de una vez
Transacciones → Tareas batch seguras
ETL → Procesos automáticos confiables
Scheduler → Orquestador del sistema
El Scheduler no es magia, es infraestructura.
Conclusión
Laravel Scheduler en producción no es solo escribir tareas, es:
Configurar correctamente el servidor
Diseñar tareas seguras
Evitar duplicados
Monitorear ejecución
Prepararse para fallos
Si el Scheduler falla, el sistema falla lentamente… y eso es lo más peligroso.