Skip to main content
Fetcher se distribuye como dos servicios. El Manager expone la API HTTP y despacha el trabajo. El Worker consume ese trabajo y produce los resultados. Ambos servicios son hosts. Ninguno contiene la lógica de extracción. Los dos ejecutan el mismo Engine en proceso, a través de los mismos puertos, bajo las mismas reglas. Ese único hecho explica el resto de esta página, y explica por qué tu propia aplicación puede ejecutar extracciones de Fetcher sin ninguno de los dos servicios.

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.
Una solicitud de creación de job responde 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 ejecuta RABBITMQ_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:
  1. Resuelve las conexiones que mapea el job y ejecuta la extracción a través del Engine embebido.
  2. Firma el JSON en texto plano con HMAC-SHA256, con una clave derivada de la clave maestra.
  3. Cifra el payload firmado con AES-GCM y lo escribe en almacenamiento de objetos compatible con S3.
  4. Publica job.completed o job.failed en el exchange que nombra RABBITMQ_JOB_EVENTS_EXCHANGE.
El Worker conduce el Engine en modo directo. El Engine devuelve los bytes exactos, y el Worker es dueño de la protección y del almacenamiento de esos bytes. Ambos eventos terminales son rutas obligatorias. El Worker se niega a arrancar cuando 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.
  • /health responde 503 hasta que la autosonda de arranque tiene éxito. El kubelet reinicia entonces un pod que no pudo alcanzar sus dependencias al arrancar.
  • /readyz ejecuta 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 /readyz con 503 durante READYZ_DRAIN_DELAY_SEC segundos, 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.