Skip to main content

Workers y colas

src/index.ts es la API y todos los workers a la vez. Lo que corre lo decide la variable de entorno EXECUTION_MODE, y en docker-compose.yml hay un container por rol.

// src/index.ts, al final
if (hasToWork()) { // EXECUTION_MODE !== "normal"
if (process.env.PAMI_SII_BOT_AUTHORIZATION?.toLowerCase() === "true")
startAutoAuthorizationLoop(); // ← cortocircuita el switch
else
mainWorker(); // WorkerConfigV2.ts
} else {
/* servidor HTTP */
}

Los modos

EXECUTION_MODEQué correContainer
vacío / normalAPI HTTP. El primary forkea APP_CORE_LIMIT workers (default = cores) y re-forkea al salir cualquieranode-app
bot-publisherScraper PAMI: publica a RabbitMQ. Ventana horaria + días hábiles + lock en Redisbot-publisher
bot-consumerConsume de la cola y persiste las autorizacionesbot-consumer-1..4
bot-authorizationSincronización de autorizaciones. Requiere además PAMI_SII_BOT_AUTHORIZATION=truebot-authorization
whatsappProcesa las colas de envío y recepción de WhatsApp
emailsWorker de correo
Un modo desconocido arranca y se apaga en silencio

mainWorker() hace process.exit(0) con un warning si el EXECUTION_MODE no matchea ningún case. El container levanta, no hace nada y se cierra. Si un worker "no hace nada", lo primero que hay que mirar es el string exacto de la variable.

Bootstrap de un worker

mainWorker() no arranca directo al trabajo: primero inicializa MySQL y Redis y corre las migraciones de datos (cache de configuración, roles, permisos, tipos de movimiento, migración de seguridad).

Es decir: levantar un worker escribe datos de configuración. No es un proceso pasivo.

Redis se vacía al arrancar

En el proceso primary, con NODE_ENV !== "dev", el arranque borra todas las claves de Redis. No guardes ahí nada que tenga que sobrevivir un deploy. Lo que sí vive en Redis:

  • ACCESSREG-<userId> — el registro de acceso del usuario (rol + permisos + unidades de gestión), con TTL CACHED_USERMETADATA_DB.
  • fetcher_lock — el lock del scraper PAMI.

Colas

src/config/bbdd/QueueConnection.ts envuelve amqplib con auto-reconexión. El broker se configura con QUEUE_URL. Ante fallos de cola se tira RabbitSyncError.

Consumidores: el bot de PAMI, el worker de WhatsApp (colas de envío y recepción por separado), el de emails y el de notificaciones push.

En docker-compose.yml hay además containers de nginx_proxy, rabbitmq (imagen rabbitmq:3.11-management, con el panel en el 15672) y socket-server.

El cluster re-forkea sin límite

cluster.on("exit") llama a fork() incondicionalmente. Un crash-loop no se auto-limita: se ve como CPU al 100% y logs repetidos, no como el container caído. Si el servicio "está arriba" pero consume todo el CPU, mirá los logs del worker antes que la infraestructura.