> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Despliegue de Fetcher

> Despliega el Manager y el Worker de Fetcher: MongoDB, RabbitMQ con cola de mensajes muertos, almacenamiento compatible con S3, Valkey o Redis, concurrencia del Worker, autoescalado y las verificaciones de arranque que detienen un servicio mal configurado.

Un despliegue independiente de Fetcher son dos servicios y cuatro dependencias. Esta página cubre qué hace cada dependencia, cómo dimensionar el Worker y qué detiene un servicio al arrancar.

Si solo necesitas extracción dentro de una aplicación Go, no despliegas nada de esto. Consulta [Embeber el Engine](/es/fetcher/fetcher-embedding-the-engine).

## Lo que despliegas

***

| Componente                    | Rol                                                                         | Escala según                       |
| ----------------------------- | --------------------------------------------------------------------------- | ---------------------------------- |
| **Manager**                   | API HTTP de conexiones y jobs. Publica trabajo en RabbitMQ.                 | Tasa de peticiones.                |
| **Worker**                    | Consumidor de cola. Ejecuta extracciones y escribe resultados.              | Profundidad de la cola.            |
| **MongoDB**                   | Registros de conexión y registros de job.                                   | Volumen de metadatos.              |
| **RabbitMQ**                  | Cola de trabajo, cola de mensajes muertos y exchange de eventos de job.     | Tasa de jobs.                      |
| **Almacenamiento de objetos** | Resultados de extracción cifrados. Compatible con S3.                       | Volumen de resultados y retención. |
| **Valkey o Redis**            | Caché de esquemas del Manager y limitador de tasa de la prueba de conexión. | Solo el Manager.                   |

## MongoDB

***

Los dos servicios se conectan al mismo despliegue de MongoDB. El Manager escribe registros de conexión y de job, y el Worker actualiza el estado de los jobs.

En modo multi-tenant, cada tenant recibe su propia base de datos, resuelta a partir de los claims del JWT de la petición. Ese camino falla cerrado: una petición que lleva una identidad de tenant sin base de datos de tenant devuelve un error en lugar de tocar la base de datos compartida.

## RabbitMQ

***

Fetcher usa tres exchanges y cuatro colas. El stack local incluido los declara por ti. En tu propio entorno, decláralos antes de que arranquen los servicios.

| Objeto                                                     | Tipo                    | Propósito                                                         |
| ---------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------- |
| `fetcher.extract-external-data.queue`                      | cola                    | Jobs de extracción, del Manager al Worker.                        |
| `fetcher.extract-external-data.exchange`                   | exchange directo        | Ligado a la cola de trabajo con la routing key `fetcher.job.key`. |
| `fetcher.dlx` y `fetcher.dlq`                              | exchange directo y cola | Mensajes muertos de la cola de trabajo.                           |
| `fetcher.job.events`                                       | exchange de tipo topic  | Eventos terminales de job.                                        |
| `fetcher.job.completed.queue` y `fetcher.job.failed.queue` | colas                   | Ligadas a `job.completed` y `job.failed`.                         |

### La cola de mensajes muertos

La cola de trabajo lleva `x-dead-letter-exchange: fetcher.dlx` y la routing key `fetcher.dlq.key`. Un mensaje que el Worker rechaza cae en `fetcher.dlq`. Esa cola retiene mensajes durante 7 días y tiene un tope de 10.000 mensajes en la configuración incluida.

Vigila la cola de mensajes muertos. Un mensaje ahí es un job que el Worker no pudo procesar.

### Eventos de job

El Worker publica `job.completed` y `job.failed` por cada job terminal. Las dos rutas son obligatorias, así que un fallo de entrega no pasa en silencio. Los consumidores se ligan a las dos colas de arriba, o ligan las suyas.

## Almacenamiento de objetos

***

El Worker escribe cada resultado almacenado en almacenamiento de objetos compatible con S3, a través del protocolo de AWS S3. AWS S3, MinIO y SeaweedFS funcionan. Alcanza SeaweedFS por su gateway S3, no por su API nativa de filer.

Dos ajustes deciden la postura de la conexión:

* El esquema de `OBJECT_STORAGE_ENDPOINT` controla TLS. Usa `https://` fuera del desarrollo local.
* `OBJECT_STORAGE_USE_PATH_STYLE=true` es lo que esperan MinIO y SeaweedFS.

### Retención de resultados

Define la retención en el bucket, con la política de ciclo de vida del propio almacén de objetos. Una regla de ciclo de vida de S3 sobre `OBJECT_STORAGE_KEY_PREFIX` expira los resultados después de la ventana que exige tu política de retención. Dale a Fetcher su propio bucket o su propio prefijo, para que la regla aplique a los resultados de extracción y a nada más.

Fetcher cifra cada resultado almacenado antes de que llegue al bucket. Consulta [Seguridad](/es/fetcher/fetcher-security).

## Valkey o Redis

***

El Manager usa Valkey o Redis para dos cosas. Cachea los esquemas de datasource descubiertos, y limita la tasa de la prueba de conexión. La variable `SCHEMA_CACHE_TTL_SECONDS` define la vida de la caché, y su valor por defecto son 5 minutos.

La caché de esquemas cae a la memoria del proceso cuando Redis está inalcanzable. El Manager sigue sirviendo. Su sonda de readiness reporta el estado de Redis por separado, así que el respaldo queda visible.

El Worker no usa la caché de esquemas.

## Concurrencia del Worker y autoescalado

***

`RABBITMQ_NUMBERS_OF_WORKERS` define cuántos jobs corre en paralelo un proceso Worker. Su valor por defecto es 5.

Dimensiónalo contra tus datasources, no contra el Worker. Cada job paralelo abre conexiones a las bases de datos que lee. Cada pool de datasource relacional tiene un tope de 25 conexiones abiertas y 10 inactivas, y MongoDB llega a 100. Dentro de una extracción, el engine corre como máximo 4 pasos de datasource a la vez.

Para escalar horizontalmente, agrega réplicas del Worker y guíalas por la profundidad de la cola de trabajo de extracción. El stack local incluido corre el operador KEDA (2.16.0) contra esa cola, así que el mismo disparador se traslada a Kubernetes.

Cada extracción lleva además límites fijos del engine. Son 10 datasources, 20 tablas por datasource y 50 campos por tabla. Una ejecución también se detiene ante un timeout de 5 minutos o un resultado serializado de 256 MiB. Una petición puede bajar cualquiera de ellos, y ninguna petición puede subirlos.

## Modo de despliegue y TLS

***

`DEPLOYMENT_MODE` declara el sabor del despliegue: `saas`, `byoc` o `local`. Etiqueta la respuesta de `/readyz`, y en `saas` exige TLS.

<Warning>
  **El modo SaaS exige TLS en todas las dependencias de plataforma.** Define `DEPLOYMENT_MODE=saas` y una URL en texto plano de MongoDB, Redis, RabbitMQ, S3 o Tenant Manager detiene el servicio. Se detiene antes de abrir cualquier conexión, y el error nombra la regla. Los datasources de tus propios tenants quedan fuera del alcance de esta verificación.
</Warning>

Deja `ALLOW_INSECURE_TLS` sin definir en producción. Permite conexiones en texto plano a MongoDB, Redis, PostgreSQL y RabbitMQ, y el entorno local incluido es el único lugar para ella.

## Verificaciones de arranque

***

Fetcher falla cerrado. Cada verificación de abajo detiene el proceso antes de que sirva tráfico.

| Disparador                                                              | Lo que ve el operador                                                                                                        |
| ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `APP_ENC_KEY` ausente, sin base64 válido o por debajo de 32 bytes       | El proceso termina al arrancar y nunca abre un puerto. El log dice `master key too short: got 0 bytes, minimum 32 required`. |
| `STREAMING_ENABLED` distinto de `true` en el Worker                     | El arranque aborta con `STREAMING_ENABLED=true is required for mandatory job event notifications`.                           |
| `RABBITMQ_JOB_EVENTS_EXCHANGE` vacío en el Worker                       | El arranque aborta con `RABBITMQ_JOB_EVENTS_EXCHANGE is required for mandatory job event notifications`.                     |
| `OBJECT_STORAGE_BUCKET` ausente en el Worker                            | El repositorio de almacenamiento no se construye, y el Worker no arranca.                                                    |
| `MULTI_TENANT_ENABLED=true` sin `MULTI_TENANT_SERVICE_API_KEY`          | El arranque aborta en ambos servicios con un error que nombra la variable.                                                   |
| Dos claves de tenant por servicio que se normalizan al mismo token      | El arranque aborta con un error que nombra el token en conflicto.                                                            |
| Modo multi-tenant con la autenticación desactivada                      | El router del Manager se niega a construirse: `tenant middleware requires effective authentication`.                         |
| `DEPLOYMENT_MODE=saas` con una dependencia de plataforma en texto plano | El arranque aborta antes de que se abra cualquier conexión.                                                                  |

<Note>
  **Una dependencia caída en el arranque no produce un pod roto en silencio.** `/health` devuelve 503 hasta que la autosonda de arranque tiene éxito. El kubelet entonces reinicia el pod en lugar de enviarle tráfico.
</Note>

## Actualizaciones progresivas

***

Ante `SIGTERM`, los dos servicios entran en drenaje. `/readyz` responde 503 durante `READYZ_DRAIN_DELAY_SEC` segundos, con un valor por defecto de 12, antes de que se cierren las conexiones. Kubernetes saca el pod de los endpoints del Service mientras este todavía atiende el trabajo en vuelo.

Define tu periodo de gracia de terminación por encima de la ventana de drenaje. Consulta [Observabilidad](/es/fetcher/fetcher-observability) para ver qué reportan las sondas durante un drenaje.

## Próximos pasos

***

<CardGroup cols={2}>
  <Card title="Configuración" icon="gear" href="/es/fetcher/fetcher-configuration">
    Todas las variables de entorno, por componente.
  </Card>

  <Card title="Seguridad" icon="shield" href="/es/fetcher/fetcher-security">
    Claves, firma, cifrado en reposo y validación de host.
  </Card>

  <Card title="Observabilidad" icon="chart-line" href="/es/fetcher/fetcher-observability">
    Sondas, comportamiento de drenaje, métricas y trazas.
  </Card>

  <Card title="Jobs de extracción" icon="list-check" href="/es/fetcher/fetcher-extraction-jobs">
    Ciclo de vida del job, estados terminales y eventos.
  </Card>
</CardGroup>
