Skip to main content
O Fetcher é distribuído como dois serviços. O Manager expõe a API HTTP e despacha o trabalho. O Worker consome esse trabalho e produz resultados. Os dois serviços são hospedeiros. Nenhum deles contém a lógica de extração. Eles rodam o mesmo Engine no próprio processo, pelas mesmas portas, sob as mesmas regras. Esse único fato explica o resto desta página, e explica por que a sua própria aplicação pode rodar a extração do Fetcher sem nenhum dos dois serviços.

Os dois serviços


Manager

O Manager segue um desenho hexagonal. Adaptadores HTTP mapeiam requisições para serviços, e os serviços alcançam a infraestrutura apenas por portas. Caminhos de leitura e caminhos de escrita ficam em pacotes de serviço separados. Ele serve doze operações em dois prefixos de caminho: Três dependências de infraestrutura sustentam a API:
  • MongoDB guarda os registros de conexão e os registros de job.
  • RabbitMQ leva um novo job até o Worker na fila que RABBITMQ_FETCHER_WORK_QUEUE nomeia.
  • Valkey ou Redis sustenta o cache de esquema e o limitador de taxa do teste de conexão. O cache de esquema cai para a memória do processo quando o Redis está inacessível.
Uma requisição de criação de job responde 202 Accepted. Uma repetição da mesma requisição dentro de uma janela de cinco minutos responde 200 OK com o job que já existe.

Worker

O Worker não tem servidor HTTP principal. Ele consome a fila de trabalho e roda RABBITMQ_NUMBERS_OF_WORKERS jobs em paralelo, cinco por padrão. Um pequeno servidor de saúde em HEALTH_PORT carrega as sondas e o endpoint de métricas. Para cada job, o Worker:
  1. Resolve as conexões que o job mapeia e roda a extração pelo Engine embarcado.
  2. Assina o JSON em texto claro com HMAC-SHA256, usando uma chave derivada da chave-mestra.
  3. Criptografa o payload assinado com AES-GCM e o grava em object storage compatível com S3.
  4. Publica job.completed ou job.failed no exchange que RABBITMQ_JOB_EVENTS_EXCHANGE nomeia.
O Worker conduz o Engine em modo direct. O Engine devolve os bytes exatos, e o Worker é dono da proteção e do armazenamento desses bytes. Os dois eventos terminais são rotas obrigatórias. O Worker se recusa a iniciar quando STREAMING_ENABLED é falso ou o exchange de eventos está em branco, porque um emissor silencioso engoliria o contrato.
O Worker fala o protocolo S3. O SeaweedFS funciona como destino de armazenamento pelo gateway compatível com S3 dele, que é como a stack local do Docker Compose roda. Defina a retenção dos resultados com uma política de ciclo de vida no bucket.

Mensagens entre eles

Toda mensagem que o Manager publica carrega uma assinatura HMAC-SHA256. O payload assinado amarra o timestamp, a versão da assinatura, o ID do tenant, o ID do job, o exchange e a routing key. O corpo vem por último. Um replay do mesmo corpo sob outro tenant ou outra rota falha na verificação. O assinador recusa qualquer chave menor que 32 bytes e compara assinaturas em tempo constante.

O Engine por baixo


O Engine é dono do que uma extração significa. Um hospedeiro é dono de como ela roda. O Engine é um módulo Go separado: github.com/LerianStudio/fetcher/pkg/engine. O go.mod dele não tem bloco require algum, e um job de CI falha o build se um aparecer. Um segundo teste imposto no build percorre toda dependência transitiva e rejeita qualquer coisa que não seja nem a biblioteca padrão do Go nem local ao módulo do Engine. Nenhum framework HTTP, nenhum cliente de fila, nenhum driver de banco de dados e nenhum SDK de nuvem consegue entrar. Essa restrição é o ponto. O Engine não acrescenta nenhuma dependência de terceiros, então uma aplicação hospedeira pode incorporá-lo sem uma única entrada nova na própria árvore de dependências.

Portas

Um hospedeiro liga o Engine por um conjunto pequeno de portas. Uma é sempre obrigatória. Uma segunda é obrigatória apenas quando a persistência criptografada está ligada. As demais são opcionais. Uma porta fornecida como nil tipado conta como ausente. O Engine detecta isso na construção, então um hospedeiro mal configurado falha na inicialização em vez de entrar em pânico na primeira chamada. O módulo também traz implementações em memória das portas de armazenamento — o registro de conectores, o connection store, o cache de esquemas, o result sink e o execution store. Isso cobre a infraestrutura que um teste precisa, então você pode exercitar o Engine sem MongoDB, sem Redis, sem RabbitMQ e sem object storage. Ele não traz um CredentialProtector, então um teste que ligue a persistência criptografada precisa fornecer o seu.

Classificação de falhas

O Engine retorna uma de onze categorias estáveis: validation, not_found, unauthorized, forbidden, limit_exceeded, conflict, unavailable, connect, timeout, canceled e internal. Um hospedeiro mapeia cada categoria para o próprio transporte. O Manager mapeia conflict para HTTP 409, por exemplo. Erros que cruzam a fronteira do Engine carregam texto fixo. O Engine descarta o erro de driver por trás de uma falha, porque esse texto pode embutir uma DSN, uma credencial ou detalhes internos do driver.

Saúde e prontidão


Os dois serviços montam /health, /readyz, /readyz/tenant/{id} e /metrics antes da autenticação, então o Kubernetes e os balanceadores de carga os alcançam sem token.
  • /health responde 503 até a autossondagem de inicialização ter sucesso. O kubelet então reinicia um pod que não conseguiu alcançar as dependências no boot.
  • /readyz roda toda sonda de dependência em paralelo a cada requisição, sem cache e com um tempo limite por dependência. O Manager sonda MongoDB, RabbitMQ e Redis. O Worker sonda MongoDB, RabbitMQ e o bucket de armazenamento. Em modo multi-tenant, os dois serviços somam o Tenant Manager e o Redis multi-tenant.
  • Em SIGTERM, os dois serviços respondem /readyz com 503 por READYZ_DRAIN_DELAY_SEC segundos, 12 por padrão, antes de derrubar as conexões. O Kubernetes remove o pod do Service enquanto ele ainda atende tráfego.

Incorporar em vez de implantar


O Manager e o Worker são hospedeiros, não camadas privilegiadas. Forneça um registro de conectores e um armazenamento de conexões, e a sua aplicação ganha o mesmo planejamento de consultas, os mesmos limites, as mesmas checagens de tenant e o mesmo formato de resultado no próprio processo. Ela não precisa de fila, de object storage nem de uma implantação separada. Os produtos Lerian incorporam o Engine exatamente assim. Leia Conceitos centrais para o modelo que o Engine implementa.

Próximos passos


Conexões

Registre, teste, atualize e exclua uma conexão com uma fonte de dados.

Configuração

As variáveis de ambiente que moldam uma implantação do Fetcher.