jobs-deploy¶
Un solo contenedor con el panel de cron y alertas (panel-cron-alertas) y los 32 jobs migrados de los 18 repos job-*, listo para desplegar en la VM Linux. Python 3.11.
Estado: piloto en pilot/jobs-deploy/. Construido y levantado en Docker Desktop (Windows) el 2026-10-14: build OK, contenedor healthy, 32 jobs cargados y smoke en verde. Falta probar los jobs con secretos reales y desplegar en la VM; ver RUNBOOK.md.
Cómo está armado¶
host (VM Linux) contenedor dabra-panel (python:3.11-slim, UID 10001)
┌───────────────────────┐ ┌────────────────────────────────────────────────────┐
│ .env (panel) │──env_file──▶ │ /app panel FastAPI + planificador │
│ secrets/<repo>.env │──ro mount──▶ │ /run/secrets/dabra/<repo>.env │
│ /var/lib/dabra │──volume───▶ │ /var/lib/dabra/<job>/ datos (DABRA_DATA_DIR) │
│ /var/log/dabra │──volume───▶ │ /data/logs/<job>/ logs de cada corrida │
│ volumen panel_data │──volume───▶ │ /data/panel.db base SQLite del panel │
└───────────────────────┘ │ /opt/dabra/jobs/<repo>/ código + .venv (en la imagen)│
│ └─ .env ─▶ /run/secrets/dabra/<repo>.env │
└────────────────────────────────────────────────────┘
panel ──(cron_expr)──▶ /opt/dabra/bin/dabra-job <repo> .venv/bin/python -m <paquete> [args]
Al arrancar, el entrypoint ejecuta python -m tools.sync_jobs --init: crea tablas y semilla, y da de alta o actualiza en el panel los 32 jobs leyendo cada job.yaml (el panel solo carga su semilla con la base vacía y no tiene API para crear jobs). Después lanza uvicorn con un único worker.
Carpetas¶
| Ruta | Qué es |
|---|---|
Dockerfile, docker-compose.yml, .env.example |
Imagen, servicio panel, plantilla de configuración del panel |
docker/ |
entrypoint.sh, dabra-job.sh (lanzador), smoke.sh (prueba de humo) |
tools/ |
preparar_contexto.py, sync_jobs.py, generar_env_example.py, verificar_env.py |
seed/ |
Semilla propia del panel: sin jobs de demo, reglas globales y reglas por job |
secrets/ |
Un <repo>.env por job (no se versiona ni entra en la imagen) |
certs/ |
CAs opcionales para el build tras un proxy/antivirus |
tests/ |
Pruebas de sync_jobs (usan el esquema real del panel) |
panel/, jobs/, MANIFEST.json |
Generados por preparar_contexto.py (en el repo real serán submódulos); no se versionan |
Decisiones y por qué¶
| Decisión | Motivo |
|---|---|
Imagen propia python:3.11-slim-bookworm con el código del panel copiado encima |
El proyecto fija 3.11 y la imagen del panel es 3.12. panel-cron-alertas no se modifica |
| Un venv por job, instalación editable | Cada job calcula REPO_DIR desde su propio archivo para leer .env, sql/ y templates/; una instalación normal los dejaría en site-packages |
uv con hardlinks para crear los 18 venvs |
Comparten pandas/numpy dentro de la capa; la imagen no se multiplica por 18 |
.env de cada job = enlace a /run/secrets/dabra/<repo>.env |
Los secretos no entran en la imagen y no chocan entre jobs (las 15 variables compartidas, como SMTP_* o TELEGRAM_TOKEN, pueden tener valores distintos por job) |
Lanzador dabra-job entre el panel y el job |
Hace cd al repo (los comandos de job.yaml son relativos) y quita del entorno las variables del panel (SMTP_*, TELEGRAM_BOT_TOKEN...) que taparían las del job, porque los jobs cargan su .env sin pisar el entorno |
| ODBC Driver 17 y 18 | Salesforce usa 17; el BYOD de ventas-online usa 18 |
| wkhtmltopdf "patched Qt" desde GitHub | El paquete de Debian no soporta las opciones de pdfkit. Solo amd64 |
sync_jobs refresca descripción/comando/rango/audit pero no cron/tolerancia/timeout/activo/ejecutar_interno |
Esos cinco se editan en el panel; --forzar los pisa |
Los 32 jobs con ejecutar_interno: true: el panel es el único ejecutor |
El contenedor contiene los jobs y puede mudarse de una VM on premise a Azure; no depende de un cron del host. Los envíos a terceros se controlan con el traspaso job por job y con el rol operator para «Ejecutar ahora» |
| El importador falla sin tumbar el panel | Un job.yaml roto no debe dejar sin alertas a los otros jobs; el error queda en docker compose logs |
Jobs incluidos (32; 30 activos)¶
| Job en el panel | Repo | Cron | Activo | Timeout (min) |
|---|---|---|---|---|
proveedores_adidas |
envio-adidas | 40 16 * * * |
si | 20 |
envio_cambio_precios |
envio-cambio-precios | 0 6 * * * |
si | 30 |
proveedores_dass_fila |
envio-dass | 0 17 * * * |
si | 9 |
proveedores_dass_asics |
envio-dass | 10 17 * * * |
si | 9 |
proveedores_dass_umbro |
envio-dass | 20 17 * * * |
si | 9 |
envia_externo_txt_ventas_keengo |
envio-keengo | 0 22 * * * |
si | 20 |
envia_externo_txt_nike |
envio-nike | 0 14 * * * |
si | 30 |
onebeat_limpieza_sftp |
envio-onebeat | 0 23 1 * * |
si | 15 |
onebeat_mtsskus |
envio-onebeat | 38 2 * * * |
si | 30 |
onebeat_catalogo_atributos |
envio-onebeat | 30 2 * * * |
si | 30 |
onebeat_transactions |
envio-onebeat | 42 2 * * * |
si | 30 |
onebeat_stocklocations |
envio-onebeat | 36 2 * * * |
si | 30 |
onebeat_status |
envio-onebeat | 51 2 * * * |
si | 30 |
onebeat_given_target |
envio-onebeat | 0 2 * * * |
si | 15 |
envio_externo_excel_proveedores |
envio-proveedores-exceso | 30 10 * * * |
si | 60 |
envia_externo_txt_puma |
envio-puma | 30 13 * * * |
si | 30 |
envia_externo_txt_topper |
envio-topper | 0 12 * * * |
si | 20 |
dolarapi_minerva |
ingesta-dolarapi | 0 19 * * * |
no | 10 |
automatizacion_bajada_modo |
ingesta-modo | 0 22 * * 1-5 |
si | 20 |
salesforce_catalogo_v4 |
ingesta-salesforce-catalogo | 0 8 * * * |
si | 20 |
salesforce_catalogo_v5 |
ingesta-salesforce-catalogo | 0 14 * * * |
si | 20 |
adf_pipelines_monitor |
monitor-adf | 0 7 * * * |
si | 120 |
adf_monitor_ir_nodes |
monitor-adf | 5 * * * * |
si | 10 |
recibe_athenas_monitor |
monitor-athenas | 20 8 * * * |
si | 20 |
recibe_performance_analisis_pbi |
monitor-pbi-performance | 30 21 * * 0,1,2,3,4 |
si | 90 |
reporte_ejecutivo_ventas |
reporte-ejecutivo-ventas | 15 8 * * * |
si | 20 |
read_sharepoint_ventas_proyectadas |
reporte-ejecutivo-ventas | 0 19 * * * |
si | 15 |
reporte_venta_online_excel |
reporte-ventas-online | 32 13,15,17,19,21 * * * |
si | 20 |
reporte_venta_online_retailtrans |
reporte-ventas-online | 37 13,15,17,19,21 * * * |
si | 20 |
reporte_retail_dia_anterior |
reporte-ventas-online | 58 7 * * * |
si | 20 |
envia_ventas_telegram |
reporte-ventas-telegram | 0 9 * * * |
si | 10 |
envia_ventas_telegram_1150 |
reporte-ventas-telegram | 50 11 * * * |
no | 10 |
Cron, tolerancia y timeout son los del job.yaml; varios están marcados "propuesto" en cada repo y se ajustan desde el panel. Los dos inactivos (dolarapi_minerva, envia_ventas_telegram_1150) siguen el estado del job.yaml. Fuera del contenedor quedan los jobs en standby del catálogo (L14, L19, L22, W06, W08, W17, W23), que no tienen repo migrado.
Límites conocidos¶
- Concurrencia: el panel ejecuta hasta 4 jobs a la vez (
ThreadPoolExecutor(4)); el resto espera en cola. Hay franjas con muchos jobs juntos (Onebeat entre 02:00 y 02:51, ventas-online a las 13:32-13:37). Con pandas en varios jobs a la vez conviene revisar la memoria de la VM. - Zona horaria:
TZpor defectoAmerica/Argentina/Buenos_Aires(la del panel). Los cron y los jobs que usan hora local dependen de ella; confirmar que coincide con el servidor actual. - Shares de backup (
PUMA_BACKUP_DIR, etc.): hay que montarlos en el contenedor (línea comentada en el compose). Sin montaje, los jobs dejan el zip enarchive/. - Red: el contenedor sale por la red del host; hacen falta las reglas de salida hacia SQL Server, los SFTP de cada tercero, Microsoft Graph, Telegram, SMTP y la API de Anthropic.
- Arquitectura: amd64 (el driver ODBC y wkhtmltopdf se instalan para esa plataforma).
- Variables opcionales:
verificar_env.pylista como faltante toda variable devariables_entornosin valor, aunque el job tenga un valor por defecto.
Fuente: repositorio jobs-deploy, versión 5bbe011. Página generada con tools/publicar_docs.py.