Skip to content

Background Jobs — Deployment & Operations

Aplica a: Fases 1-3 (producción)


Prerequisitos

RequisitoDetalle
SupervisorInstalado en el servidor (supervisord disponible en PATH)
CronDisponible en el servidor (crontab -e funcional)
PHP/usr/bin/php accesible por el usuario que corre el worker
Usuariowww-data (o equivalente con acceso al directorio del proyecto)
Logs directory{PROJECT_ROOT}/logs/ creado y con permisos de escritura para www-data

Instalar Supervisor

bash
# Ubuntu/Debian
sudo apt install supervisor

# CentOS/RHEL
sudo yum install supervisor

Procesos a gestionar

ProcesoTipoPropósito
bin/worker.phpDaemon long-running (Supervisor)Heartbeat, safety-net retry (5 min), stale cleanup en tiempo real
cli/cleanup-stale-jobs.php --days=30Tarea periódica diaria (Crontab)Elimina jobs con más de 30 días de antigüedad

Nota sobre retries: El mecanismo principal de retry es el self-dispatch dentro de JobExecutor: al fallar un job con reintentos disponibles, el executor re-despacha el worker CLI directamente. El daemon bin/worker.php actúa como safety-net con un intervalo de 5 minutos, reintentando jobs pendientes cuyo self-dispatch pudo haber fallado (ej: proceso terminado antes de completar el dispatch). El archivo retry-scheduler.php fue eliminado; ya no se depende de cron para scheduling de retries.


Variables de Entorno Requeridas

El worker lee la configuración desde {PROJECT_ROOT}/.env:

env
DB_HOST=localhost
DB_PORT=5432
DB_NAME=empresa_xyz
DB_USER=postgres
DB_PASS=secret
ENABLE_BACKGROUND_JOBS=true

Configuración de Supervisor

Plantilla provista por el proyecto

El proyecto incluye supervisor/bautista-worker.conf.dist con {PROJECT_ROOT} como placeholder. Copiarla y reemplazar el placeholder antes de activar:

bash
cp {PROJECT_ROOT}/supervisor/bautista-worker.conf.dist /etc/supervisor/conf.d/bautista-worker.conf

Reemplazar {PROJECT_ROOT} en el archivo copiado con la ruta absoluta real del proyecto (por ejemplo /var/www/mi-proyecto).

Contenido del archivo de configuración

ini
[program:bautista-worker]
command=/usr/bin/php {PROJECT_ROOT}/bin/worker.php
directory={PROJECT_ROOT}
user=www-data
autostart=true
autorestart=true
startretries=5
startsecs=3
stopwaitsecs=10
redirect_stderr=true
stdout_logfile={PROJECT_ROOT}/logs/background-jobs.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
environment=APP_ENV="production"

Aplicar la configuración

bash
# Recargar configuración de Supervisor
sudo supervisorctl reread
sudo supervisorctl update

# Verificar que el worker arrancó
sudo supervisorctl status bautista-worker

Configuración de Crontab

La limpieza periódica se configura como una línea de crontab bajo el usuario www-data:

bash
sudo crontab -u www-data -e

Agregar la siguiente línea (reemplazar {PROJECT_ROOT} con la ruta absoluta real):

bash
0 2 * * * /usr/bin/php {PROJECT_ROOT}/cli/cleanup-stale-jobs.php --days=30 >> {PROJECT_ROOT}/logs/cleanup.log 2>&1

El cleanup se ejecuta todos los días a las 02:00. La salida (stdout y stderr) se acumula en logs/cleanup.log.


Comandos Operacionales

Estado y control del worker

bash
# Ver estado del worker
sudo supervisorctl status bautista-worker

# Reiniciar el worker (obligatorio después de cada deploy)
sudo supervisorctl restart bautista-worker

# Detener el worker
sudo supervisorctl stop bautista-worker

# Iniciar el worker manualmente
sudo supervisorctl start bautista-worker

Logs del worker

bash
# Ver log en tiempo real
tail -f {PROJECT_ROOT}/logs/background-jobs.log

# Ver últimas 100 líneas
tail -n 100 {PROJECT_ROOT}/logs/background-jobs.log

# Debug via Supervisor (stderr capturado junto a stdout)
sudo supervisorctl tail bautista-worker stderr

Cleanup manual

bash
# Simulación sin eliminar (dry-run)
/usr/bin/php {PROJECT_ROOT}/cli/cleanup-stale-jobs.php --days=30 --dry-run

# Ejecución real
/usr/bin/php {PROJECT_ROOT}/cli/cleanup-stale-jobs.php --days=30

Manejar jobs fallidos via API

bash
# Listar jobs fallidos
GET /jobs?status=failed

# Retry manual de un job específico
POST /jobs/{id}/retry

Verificación de Salud

Después del setup inicial, confirmar que todo está corriendo:

bash
# 1. Supervisor reporta el worker como RUNNING
sudo supervisorctl status bautista-worker
# Resultado esperado: bautista-worker    RUNNING   pid 12345, uptime 0:01:23

# 2. Log del worker tiene actividad reciente
tail -n 20 {PROJECT_ROOT}/logs/background-jobs.log

# 3. Health check HTTP (requiere servidor corriendo)
curl http://localhost/jobs/health

# 4. Verificar que el crontab está configurado para www-data
sudo crontab -u www-data -l

Apagado Graceful

El daemon bin/worker.php maneja SIGTERM limpiamente: termina la iteración en curso antes de detenerse. Supervisor envía SIGTERM al detener el proceso y espera hasta stopwaitsecs=10 antes de forzar SIGKILL.

bash
# Detener limpiamente (Supervisor envía SIGTERM, espera 10s)
sudo supervisorctl stop bautista-worker

# Verificar que se detuvo
sudo supervisorctl status bautista-worker
# Resultado esperado: bautista-worker    STOPPED

Monitoreo Prometheus

El endpoint /jobs/metrics expone métricas en formato Prometheus:

bautista_jobs_total{status="completed"} 1423
bautista_jobs_total{status="failed"}    12
bautista_jobs_total{status="running"}   2
bautista_jobs_total{status="pending"}   5
bautista_jobs_p95_duration_seconds      47.2

Agregar al prometheus.yml:

yaml
scrape_configs:
  - job_name: bautista-background-jobs
    static_configs:
      - targets: ['localhost:80']
    metrics_path: /jobs/metrics

Última actualización: 2026-03-12