> ## 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.

# Implantação do Fetcher

> Implante o Manager e o Worker do Fetcher: MongoDB, RabbitMQ com dead-letter queue, storage compatível com S3, Valkey ou Redis, concorrência do Worker, autoescala e as checagens de inicialização que param um serviço mal configurado.

Uma implantação autônoma do Fetcher são dois serviços e quatro dependências. Esta página cobre o que cada dependência faz, como dimensionar o Worker e o que interrompe um serviço na inicialização.

Se você só precisa de extração dentro de uma aplicação Go, não implanta nada disso. Veja [Embarcando o Engine](/pt/fetcher/fetcher-embedding-the-engine).

## O que você implanta

***

| Componente          | Papel                                                                | Escala por                       |
| ------------------- | -------------------------------------------------------------------- | -------------------------------- |
| **Manager**         | API HTTP para conexões e jobs. Publica trabalho no RabbitMQ.         | Taxa de requisições.             |
| **Worker**          | Consumidor de fila. Roda extrações e grava resultados.               | Profundidade da fila.            |
| **MongoDB**         | Registros de conexão e registros de job.                             | Volume de metadados.             |
| **RabbitMQ**        | Fila de trabalho, dead-letter queue e o exchange de eventos de job.  | Taxa de jobs.                    |
| **Object storage**  | Resultados de extração criptografados. Compatível com S3.            | Volume de resultados e retenção. |
| **Valkey ou Redis** | Cache de esquema do Manager e limitador de taxa do teste de conexão. | Apenas o Manager.                |

## MongoDB

***

Os dois serviços conectam à mesma implantação de MongoDB. O Manager grava registros de conexão e de job, e o Worker atualiza o estado do job.

Em modo multi-tenant, cada tenant recebe o próprio banco, resolvido a partir das claims do JWT na requisição. Esse caminho falha de forma fechada: uma requisição que carrega uma identidade de tenant sem banco de tenant retorna um erro em vez de tocar o banco compartilhado.

## RabbitMQ

***

O Fetcher usa três exchanges e quatro filas. A stack local que acompanha o repositório os declara para você. No seu próprio ambiente, declare-os antes de os serviços subirem.

| Objeto                                                     | Tipo                   | Finalidade                                                     |
| ---------------------------------------------------------- | ---------------------- | -------------------------------------------------------------- |
| `fetcher.extract-external-data.queue`                      | fila                   | Jobs de extração, do Manager para o Worker.                    |
| `fetcher.extract-external-data.exchange`                   | exchange direct        | Ligado à fila de trabalho com a routing key `fetcher.job.key`. |
| `fetcher.dlx` e `fetcher.dlq`                              | exchange direct e fila | Dead letters da fila de trabalho.                              |
| `fetcher.job.events`                                       | exchange topic         | Eventos terminais de job.                                      |
| `fetcher.job.completed.queue` e `fetcher.job.failed.queue` | filas                  | Ligadas a `job.completed` e `job.failed`.                      |

### A dead-letter queue

A fila de trabalho carrega `x-dead-letter-exchange: fetcher.dlx` e a routing key `fetcher.dlq.key`. Uma mensagem que o Worker rejeita cai em `fetcher.dlq`. Essa fila guarda mensagens por 7 dias e limita em 10.000 mensagens na configuração que acompanha o repositório.

Monitore a dead-letter queue. Uma mensagem ali é um job que o Worker não conseguiu processar.

### Eventos de job

O Worker publica `job.completed` e `job.failed` para todo job terminal. As duas rotas são obrigatórias, então uma falha de entrega não é silenciosa. Consumidores ligam-se às duas filas acima, ou ligam as próprias.

## Object storage

***

O Worker grava cada resultado armazenado em object storage compatível com S3, pelo protocolo S3 da AWS. AWS S3, MinIO e SeaweedFS funcionam. Alcance o SeaweedFS pelo gateway S3 dele, e não pela API nativa de filer.

Duas configurações decidem a postura da conexão:

* O esquema em `OBJECT_STORAGE_ENDPOINT` controla o TLS. Use `https://` fora do desenvolvimento local.
* `OBJECT_STORAGE_USE_PATH_STYLE=true` é o que MinIO e SeaweedFS esperam.

### Retenção de resultados

Defina a retenção no bucket, com a política de ciclo de vida do próprio object storage. Uma regra de ciclo de vida S3 sobre `OBJECT_STORAGE_KEY_PREFIX` expira os resultados depois da janela que a sua política de retenção exige. Dê ao Fetcher um bucket próprio ou um prefixo próprio, para que a regra se aplique aos resultados de extração e a mais nada.

O Fetcher criptografa todo resultado armazenado antes de ele chegar ao bucket. Veja [Segurança](/pt/fetcher/fetcher-security).

## Valkey ou Redis

***

O Manager usa Valkey ou Redis para duas coisas. Ele guarda em cache os esquemas de fonte de dados descobertos, e limita a taxa do teste de conexão. A variável `SCHEMA_CACHE_TTL_SECONDS` define a vida do cache, e o padrão dela é 5 minutos.

O cache de esquema cai para a memória do processo quando o Redis está inacessível. O Manager continua atendendo. A sonda de prontidão dele reporta o estado do Redis em separado, então o fallback continua visível.

O Worker não usa o cache de esquema.

## Concorrência e autoescala do Worker

***

`RABBITMQ_NUMBERS_OF_WORKERS` define quantos jobs um processo Worker roda em paralelo. O padrão é 5.

Dimensione contra as suas fontes de dados, e não contra o Worker. Cada job paralelo abre conexões com os bancos que lê. Todo pool de fonte de dados relacional limita em 25 conexões abertas e 10 ociosas, e o MongoDB limita em 100. Dentro de uma extração, o Engine roda no máximo 4 passos de fonte de dados por vez.

Para escala horizontal, adicione réplicas do Worker e comande-as pela profundidade da fila de trabalho de extração. A stack local que acompanha o repositório roda o operador KEDA (2.16.0) contra essa fila, então o mesmo gatilho vale no Kubernetes.

Toda extração também carrega limites fixos do Engine. Eles são 10 fontes de dados, 20 tabelas por fonte de dados e 50 campos por tabela. Uma execução também para em um tempo limite de 5 minutos ou em um resultado serializado de 256 MiB. Uma requisição pode baixar qualquer um deles, e nenhuma requisição pode elevá-los.

## Modo de implantação e TLS

***

`DEPLOYMENT_MODE` declara o sabor da implantação: `saas`, `byoc` ou `local`. Ele etiqueta a resposta de `/readyz` e, em `saas`, exige TLS.

<Warning>
  **O modo SaaS exige TLS em toda dependência de plataforma.** Defina `DEPLOYMENT_MODE=saas` e uma URL em texto claro de MongoDB, Redis, RabbitMQ, S3 ou Tenant Manager interrompe o serviço. A parada ocorre antes de qualquer conexão abrir, e o erro nomeia a regra. As fontes de dados dos seus próprios tenants ficam fora do escopo dessa checagem.
</Warning>

Deixe `ALLOW_INSECURE_TLS` sem definir em produção. Ela permite conexões em texto claro com MongoDB, Redis, PostgreSQL e RabbitMQ, e o ambiente local que acompanha o repositório é o único lugar para ela.

## Checagens de inicialização

***

O Fetcher falha de forma fechada. Cada checagem abaixo interrompe o processo antes de ele atender tráfego.

| Gatilho                                                                 | O que o operador vê                                                                                                              |
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `APP_ENC_KEY` ausente, fora de base64 ou com menos de 32 bytes          | O processo encerra na inicialização e nunca abre uma porta. O log traz `master key too short: got 0 bytes, minimum 32 required`. |
| `STREAMING_ENABLED` diferente de `true` no Worker                       | A inicialização aborta com `STREAMING_ENABLED=true is required for mandatory job event notifications`.                           |
| `RABBITMQ_JOB_EVENTS_EXCHANGE` em branco no Worker                      | A inicialização aborta com `RABBITMQ_JOB_EVENTS_EXCHANGE is required for mandatory job event notifications`.                     |
| `OBJECT_STORAGE_BUCKET` ausente no Worker                               | O repositório de armazenamento não sobe, e o Worker não inicia.                                                                  |
| `MULTI_TENANT_ENABLED=true` sem `MULTI_TENANT_SERVICE_API_KEY`          | A inicialização aborta nos dois serviços, com um erro que nomeia a variável.                                                     |
| Duas chaves de tenant por serviço que normalizam para o mesmo token     | A inicialização aborta com um erro que nomeia o token em conflito.                                                               |
| Modo multi-tenant com a autenticação desligada                          | O roteador do Manager se recusa a subir: `tenant middleware requires effective authentication`.                                  |
| `DEPLOYMENT_MODE=saas` com uma dependência de plataforma em texto claro | A inicialização aborta antes de qualquer conexão abrir.                                                                          |

<Note>
  **Uma dependência fora do ar no boot não produz um pod quebrado em silêncio.** O `/health` retorna 503 até a autossondagem de inicialização passar. O kubelet então reinicia o pod, em vez de mandar tráfego para ele.
</Note>

## Atualizações contínuas

***

Em `SIGTERM`, os dois serviços entram em drenagem. O `/readyz` responde 503 por `READYZ_DRAIN_DELAY_SEC` segundos, 12 por padrão, antes de as conexões serem derrubadas. O Kubernetes remove o pod dos endpoints do Service enquanto ele ainda atende o trabalho em voo.

Defina o período de graça de término acima da janela de drenagem. Veja [Observabilidade](/pt/fetcher/fetcher-observability) para o que as sondas reportam durante uma drenagem.

## Próximos passos

***

<CardGroup cols={2}>
  <Card title="Configuração" icon="gear" href="/pt/fetcher/fetcher-configuration">
    Cada variável de ambiente, por componente.
  </Card>

  <Card title="Segurança" icon="shield" href="/pt/fetcher/fetcher-security">
    Chaves, assinatura, criptografia em repouso e validação de host.
  </Card>

  <Card title="Observabilidade" icon="chart-line" href="/pt/fetcher/fetcher-observability">
    Sondas, comportamento de drenagem, métricas e tracing.
  </Card>

  <Card title="Jobs de extração" icon="list-check" href="/pt/fetcher/fetcher-extraction-jobs">
    Ciclo de vida do job, estados terminais e eventos.
  </Card>
</CardGroup>
