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_QUEUEnomeia. - 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.
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 rodaRABBITMQ_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:
- Resolve as conexões que o job mapeia e roda a extração pelo Engine embarcado.
- Assina o JSON em texto claro com HMAC-SHA256, usando uma chave derivada da chave-mestra.
- Criptografa o payload assinado com AES-GCM e o grava em object storage compatível com S3.
- Publica
job.completedoujob.failedno exchange queRABBITMQ_JOB_EVENTS_EXCHANGEnomeia.
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.
/healthresponde 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./readyzroda 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/readyzcom 503 porREADYZ_DRAIN_DELAY_SECsegundos, 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.

