Los dos servicios
Manager
El Manager sigue un diseño hexagonal. Los adaptadores HTTP mapean las solicitudes hacia los servicios, y los servicios llegan a la infraestructura solo a través de puertos. Los caminos de lectura y los de escritura viven en paquetes de servicio separados. Sirve doce operaciones en dos prefijos de ruta:
Tres dependencias de infraestructura respaldan la API:
- MongoDB guarda los registros de conexión y los registros de job.
- RabbitMQ lleva un job nuevo hasta el Worker por la cola que nombra
RABBITMQ_FETCHER_WORK_QUEUE. - Valkey o Redis respalda la caché de esquemas y el limitador de tasa de la prueba de conexión. La caché de esquemas recurre a la memoria del proceso cuando Redis está inalcanzable.
202 Accepted. Una repetición de la misma solicitud dentro de una ventana de cinco minutos responde 200 OK con el job que ya existe.
Worker
El Worker no tiene servidor HTTP principal. Consume la cola de trabajo y ejecutaRABBITMQ_NUMBERS_OF_WORKERS jobs en paralelo, cinco por defecto. Un pequeño servidor de salud en HEALTH_PORT lleva las sondas y el endpoint de métricas.
Para cada job, el Worker:
- Resuelve las conexiones que mapea el job y ejecuta la extracción a través del Engine embebido.
- Firma el JSON en texto plano con HMAC-SHA256, con una clave derivada de la clave maestra.
- Cifra el payload firmado con AES-GCM y lo escribe en almacenamiento de objetos compatible con S3.
- Publica
job.completedojob.faileden el exchange que nombraRABBITMQ_JOB_EVENTS_EXCHANGE.
STREAMING_ENABLED es false o el exchange de eventos está vacío, porque un emisor silencioso que no hace nada se tragaría el contrato.
El Worker habla el protocolo S3. SeaweedFS funciona como destino de almacenamiento a través de su gateway compatible con S3, que es como corre el stack local de Docker Compose. Define la retención de los resultados con una política de ciclo de vida en el bucket.
Mensajes entre ellos
Cada mensaje que publica el Manager lleva una firma HMAC-SHA256. El payload firmado une el timestamp, la versión de firma, el ID de tenant, el ID de job, el exchange y la routing key. El cuerpo va al final. Un replay del mismo cuerpo bajo otro tenant o por otra ruta falla la verificación. El firmante rechaza cualquier clave menor a 32 bytes y compara las firmas en tiempo constante.El Engine por debajo
El Engine es dueño de lo que una extracción significa. Un host es dueño de cómo se ejecuta.
El Engine es un módulo Go separado:
github.com/LerianStudio/fetcher/pkg/engine. Su go.mod no lleva ningún bloque require, y un job de CI falla la compilación si aparece uno. Una segunda prueba, forzada por la compilación, recorre cada dependencia transitiva y rechaza todo lo que no sea la biblioteca estándar de Go o local al módulo del Engine. Ningún framework HTTP, ningún cliente de cola, ningún driver de base de datos y ningún SDK de nube puede entrar.
Esa restricción es el punto. El Engine no agrega ninguna dependencia de terceros, así que una aplicación host puede embeberlo sin una sola entrada nueva en su propio árbol de dependencias.
Puertos
Un host conecta el Engine mediante un conjunto pequeño de puertos. Uno es siempre obligatorio. Un segundo lo es solo cuando la persistencia cifrada está activada. El resto son opcionales.
Un puerto provisto como nil tipado cuenta como ausente. El Engine lo detecta en la construcción, así que un host mal configurado falla en el arranque en lugar de romperse en la primera llamada.
El módulo también incluye implementaciones en memoria de los puertos de almacenamiento — el registro de conectores, el connection store, la caché de esquemas, el result sink y el execution store. Eso cubre la infraestructura que un test necesita, así que puedes ejercitar el Engine sin MongoDB, sin Redis, sin RabbitMQ y sin almacenamiento de objetos. No incluye un
CredentialProtector, así que un test que active la persistencia cifrada debe aportar el suyo.
Clasificación de fallos
El Engine devuelve una de once categorías estables:validation, not_found, unauthorized, forbidden, limit_exceeded, conflict, unavailable, connect, timeout, canceled e internal. Un host mapea cada categoría a su propio transporte. El Manager mapea conflict a HTTP 409, por ejemplo.
Los errores que cruzan la frontera del Engine llevan texto fijo. El Engine descarta el error del driver que hay detrás de un fallo, porque ese texto puede incluir un DSN, una credencial o detalles internos del driver.
Salud y readiness
Ambos servicios montan
/health, /readyz, /readyz/tenant/{id} y /metrics antes de la autenticación, para que Kubernetes y los balanceadores de carga los alcancen sin un token.
/healthresponde 503 hasta que la autosonda de arranque tiene éxito. El kubelet reinicia entonces un pod que no pudo alcanzar sus dependencias al arrancar./readyzejecuta cada sonda de dependencia en paralelo en cada solicitud, sin caché y con un timeout por dependencia. El Manager sondea MongoDB, RabbitMQ y Redis. El Worker sondea MongoDB, RabbitMQ y el bucket de almacenamiento. En modo multi-tenant, ambos servicios agregan el Tenant Manager y el Redis multi-tenant.- Con
SIGTERM, ambos servicios responden/readyzcon 503 duranteREADYZ_DRAIN_DELAY_SECsegundos, 12 por defecto, antes de cerrar las conexiones. Kubernetes saca el pod del Service mientras este todavía atiende tráfico.
Embeber en lugar de desplegar
El Manager y el Worker son hosts, no capas privilegiadas. Provee un registro de conectores y un almacén de conexiones, y tu aplicación obtiene la misma planificación de consultas, los mismos límites, las mismas verificaciones de tenant y la misma forma de resultado en proceso. No necesita cola, ni almacenamiento de objetos, ni un despliegue aparte. Los productos de Lerian embeben el Engine exactamente así. Lee Conceptos centrales para conocer el modelo que implementa el Engine.
Próximos pasos
Conexiones
Registra, prueba, actualiza y elimina una conexión a un datasource.
Configuración
Las variables de entorno que dan forma a un despliegue de Fetcher.

