Saltar al contenido principal

Scheduler + Cron — Setup OnnixConnect

Ticket Jira: FAC-83 — Configurar Laravel Scheduler + cron en servidor Estado: Demo en local funcionando 2026-04-09. Falta deploy en server.


Qué resuelve

Reemplazar todos los procesos manuales y los crons individuales por un único punto de entrada (schedule:run) que Laravel maneja internamente. La cron del SO solo tiene que dispararlo cada minuto.

Tareas programadas activas hoy:

Comando / JobFrecuenciaDefinido en
App\Jobs\Sifen\SincronizarEstadosSifenJobcada 5 minroutes/console.php:15

A futuro se irán agregando más (reportes diarios, limpieza de logs, etc.) sin tocar el cron del servidor — solo agregando líneas en routes/console.php.


Cómo se prueba en local

1. Verificar lo que está programado

php artisan schedule:list

Debe mostrar:

*/5 * * * * App\Jobs\Sifen\SincronizarEstadosSifenJob Next Due: X minutes from now

2. Levantar el "cron simulado" + worker de cola

En dos terminales separadas (o background):

# Terminal 1 — simula el cron del servidor llamando schedule:run cada minuto
php artisan schedule:work

# Terminal 2 — procesa los jobs encolados (en producción esto lo hace Horizon)
php artisan queue:work --queue=default

3. Disparar manualmente sin esperar al boundary de 5 min

php artisan schedule:test --name="App\Jobs\Sifen\SincronizarEstadosSifenJob"

schedule:test bypaseа la expresión cron y encola el job inmediatamente. El worker de cola lo procesa en milisegundos.

4. Demo completo end-to-end (probado 2026-04-09)

1. Crear DTE → firmar → enviar como lote → quedar en 'sent'
2. Forzar last_sent_at a -10 min para pasar el filtro del job
3. schedule:test --name=SincronizarEstadosSifenJob
→ Running [SincronizarEstadosSifenJob] ........... 20.47ms DONE
4. Queue worker (background)
→ 2026-04-09 17:42:35 SincronizarEstadosSifenJob ...... RUNNING
→ 2026-04-09 17:42:35 SincronizarEstadosSifenJob 225.48ms DONE
5. SELECT estado, sifen_result_code FROM sifen_dtes WHERE id=93
→ estado=approved, cod=0260, msg=Aprobado ✅

Setup en servidor de desarrollo

Pre-requisitos

  • PHP 8.2+ con php artisan accesible.
  • El proyecto desplegado en una ruta conocida (ej. /var/www/onnixconnect).
  • Usuario del sistema con permisos sobre el proyecto (ej. www-data o nestor).
  • Redis corriendo (la cola default apunta a Redis).
  • Horizon (o queue:work como fallback) corriendo como servicio supervisado.

Paso 1 — Agregar el cron del sistema

Editar el crontab del usuario que corre la aplicación:

sudo -u www-data crontab -e

Agregar una sola línea:

* * * * * cd /var/www/onnixconnect && php artisan schedule:run >> /dev/null 2>&1

Notas:

  • * * * * * = cada minuto (Laravel internamente decide qué tareas son due).
  • cd /var/www/onnixconnect es OBLIGATORIO — schedule:run necesita el cwd del proyecto.
  • Redirigir la salida a /dev/null evita que el crond mande mails. Si querés ver los logs cambialos a un archivo: >> /var/log/onnixconnect/schedule.log 2>&1.

Verificar que el crontab quedó guardado:

sudo -u www-data crontab -l

Paso 2 — Confirmar que crond está corriendo

systemctl status cron # Debian/Ubuntu
systemctl status crond # CentOS/RHEL

Si no está activo: sudo systemctl enable --now cron.

Paso 3 — Configurar Horizon como servicio (FAC-96 en el roadmap)

Hasta que FAC-96 esté hecho, se puede usar queue:work directo bajo supervisor. Archivo de ejemplo /etc/supervisor/conf.d/onnixconnect-worker.conf:

[program:onnixconnect-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/onnixconnect/artisan queue:work redis --queue=critica,lotes,default --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/log/onnixconnect/worker.log
stopwaitsecs=3600

Aplicar:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start onnixconnect-worker:*

Paso 4 — Smoke test en el server

# 1. Listar tareas programadas
sudo -u www-data php /var/www/onnixconnect/artisan schedule:list

# 2. Forzar ejecución manual
sudo -u www-data php /var/www/onnixconnect/artisan schedule:test --name="App\Jobs\Sifen\SincronizarEstadosSifenJob"

# 3. Ver logs del cron en vivo (cada minuto debe haber actividad)
tail -f /var/log/onnixconnect/schedule.log # si configuraste el log
# o
journalctl -u cron -f # logs del propio crond

# 4. Verificar que el worker está vivo
sudo supervisorctl status onnixconnect-worker:*

Paso 5 — Validación funcional

Con el sistema configurado:

  1. Enviar un lote real vía POST /api/sifen/dtes/lote.
  2. Verificar en BD que los DTEs quedan en estado=sent con prot_lote poblado.
  3. Esperar 5-10 minutos.
  4. Re-consultar BD: deben transicionar automáticamente a approved o rejected.

Si después de 10 min no hubo transición, debuggear en este orden:

  • ¿El cron está disparando? grep CRON /var/log/syslog | tail
  • ¿schedule:run está corriendo el job? php artisan schedule:list y verificar "Last Due"
  • ¿El worker está vivo? supervisorctl status
  • ¿Hay jobs en la cola Redis? redis-cli LLEN queues:default
  • ¿Hay jobs fallidos? php artisan queue:failed

Cómo agregar más tareas programadas

Editar routes/console.php y agregar líneas como:

use App\Jobs\Reportes\GenerarReporteDiarioJob;

Schedule::job(new GenerarReporteDiarioJob())->dailyAt('06:00');
Schedule::command('horizon:snapshot')->everyFiveMinutes();
Schedule::command('telescope:prune --hours=48')->daily();

No hay que tocar el cron del sistema. Solo recargar la app si está cacheada (php artisan optimize:clear).


Troubleshooting

SíntomaCausa probableSolución
schedule:run no hace nadaEl cron no está pasando por el cwd correctoVerificar cd /var/www/onnixconnect && en el crontab
schedule:list no muestra el jobroutes/console.php no se está cargandophp artisan optimize:clear y reintentar
Job se encola pero no se procesaWorker caído o cola incorrectasupervisorctl status + verificar --queue=default
WithoutOverlapping bloquea siempreLock viejo en cachephp artisan cache:clear
Logs vacíos>> /dev/null 2>&1 está silenciando todoCambiar a >> /var/log/onnixconnect/schedule.log 2>&1 para debug

Referencias

  • Laravel 12 — Task Scheduling
  • Laravel Horizon
  • routes/console.php — definición de tareas programadas
  • app/Jobs/Sifen/SincronizarEstadosSifenJob.php — el job que corre cada 5 min
  • docs/guias-tecnicas/SIFEN_LOTE_ASYNC_FUNCIONAMIENTO.md — pipeline completo de lotes async