RepoLens Worker
RepoLens Worker recebe solicitações versionadas, clona repositórios públicos do GitHub em um
diretório temporário, executa o repolens-core sem importar ou executar código do repositório e
publica o relatório normalizado no repolens-api.
Visão geral
mensagem JSON
↓
Dramatiq → Redis → Worker → clone Git temporário → RepoLens Core
↓
PostgreSQL ← RepoLens API ← relatório autenticado ──┘
| Serviço | Responsabilidade | Porta local |
|---|---|---|
postgres |
Persistência do RepoLens API | somente rede do Compose |
redis |
Fila, estado e claims de idempotência | 6379 |
api |
Instala repolens-api via pip e recebe relatórios |
8000 |
worker |
Consome jobs, clona, analisa e publica | métricas internas em 9000 |
O processador síncrono concentra as regras de negócio e depende de portas substituíveis para Git, Core, API e estado. A fronteira Dramatiq converte a mensagem, registra o resultado, agenda retries e encaminha falhas terminais para a dead-letter queue.
Requisitos
- Docker com Docker Compose;
curlejqpara o exemplo local;- acesso à internet para instalar os pacotes e clonar o repositório público de demonstração;
- Python 3.13 apenas para desenvolvimento fora dos containers.
Instalação via PyPI
Depois da primeira publicação, o pacote e o produtor de mensagens podem ser instalados com:
python3.13 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install repolens-worker
O comando repolens-worker-enqueue lê uma mensagem JSON de stdin e a envia ao Redis configurado
por REDIS_URL. O consumidor é iniciado com:
dramatiq repolens_worker.worker --processes 1 --threads 4
Para a experiência local completa, incluindo API e banco, prefira o Compose descrito a seguir.
Teste local completo — caminho recomendado
Crie a configuração local e execute o script de demonstração:
cp .env.example .env
./scripts/local_demo.sh
Esse único script:
- sobe PostgreSQL, Redis e RepoLens API;
- aguarda o healthcheck da API;
- cria um projeto com credencial administrativa local;
- captura o
project_id; - cria e captura o token de ingestão, exibido apenas uma vez pela API;
- salva as credenciais em
.env.localcom permissão restrita; - inicia o serviço
workernormal do Compose; - enfileira
https://github.com/Jonatanjrss/repolens-core; - aguarda e imprime o relatório persistido.
.env.local e .env são ignorados pelo Git. O script não imprime o token no terminal e nunca o
coloca na mensagem da fila.
Para analisar outro repositório público do GitHub:
REPOSITORY_URL=https://github.com/owner/repository ./scripts/local_demo.sh
Fluxo manual
Use esta seção quando quiser entender ou depurar cada etapa.
1. Iniciar infraestrutura e API
cp .env.example .env
docker compose up -d postgres redis api
until curl -fsS http://localhost:8000/health >/dev/null; do sleep 2; done
O serviço api instala repolens-api==0.1.0 via pip. Como o pacote publicado não distribui os
arquivos Alembic, o Compose cria as tabelas com o metadata SQLAlchemy exclusivamente para o
ambiente local. Em produção, use migrations versionadas gerenciadas pelo deploy da API.
Altere REPOLENS_API_VERSION em .env para testar outra versão publicada. A primeira inicialização
pode levar alguns instantes enquanto o container instala as dependências.
2. Criar projeto e token
PROJECT_SLUG="local-repolens-$(date +%s)"
PROJECT_JSON="$(curl -fsS -X POST http://localhost:8000/v1/projects \
-H "X-Admin-Key: ${REPOLENS_ADMIN_API_KEY:-local-admin-key}" \
-H 'Content-Type: application/json' \
-d "{\"name\":\"Local RepoLens\",\"slug\":\"${PROJECT_SLUG}\",\"repository_url\":\"https://github.com/Jonatanjrss/repolens-core\"}")"
PROJECT_ID="$(printf '%s' "$PROJECT_JSON" | jq -er '.id')"
TOKEN_JSON="$(curl -fsS -X POST \
"http://localhost:8000/v1/projects/${PROJECT_ID}/tokens" \
-H "X-Admin-Key: ${REPOLENS_ADMIN_API_KEY:-local-admin-key}")"
REPO_API_TOKEN="$(printf '%s' "$TOKEN_JSON" | jq -er '.token')"
export PROJECT_ID REPO_API_TOKEN
O token pertence ao projeto indicado por PROJECT_ID. Trocar o projeto e reutilizar um token
antigo retorna 401 Unauthorized. Se um token aparecer em logs, histórico compartilhado ou uma
mensagem pública, considere-o comprometido e crie outro projeto/token para o teste.
3. Iniciar o worker
export REPO_PROJECT_ID="$PROJECT_ID"
export REPO_API_TOKEN
docker compose up -d --build worker
Usar docker compose up mantém o worker como serviço do projeto e evita containers órfãos e
conflitos de nome causados por docker compose run --name ....
4. Enfileirar uma análise
jq -n \
--arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg job_id "job-$(date +%s)" \
'{version: 1, job_id: $job_id, repository_url: "https://github.com/Jonatanjrss/repolens-core", ref: "main", requested_at: $now, attempt: 0}' \
| docker compose exec -T worker python -m repolens_worker.cli
Use uma URL simples no JSON. A sintaxe Markdown [https://...](https://...) não é uma URL de
repositório válida.
5. Consultar o resultado
curl -fsS "http://localhost:8000/v1/projects/${PROJECT_ID}/runs" \
-H "Authorization: Bearer ${REPO_API_TOKEN}" \
| jq .
Para recuperar as variáveis salvas pelo script em outro terminal:
set -a
. ./.env.local
set +a
PROJECT_ID="$REPO_PROJECT_ID"
Contrato da mensagem
{
"version": 1,
"job_id": "job-123",
"repository_url": "https://github.com/owner/repository",
"ref": "main",
"requested_at": "2026-08-29T12:00:00+00:00",
"attempt": 0,
"commit": "0123456789abcdef0123456789abcdef01234567"
}
commit é opcional. job_id é a chave estável de idempotência e attempt começa em zero. A URL
deve usar HTTPS, não pode conter credenciais, query ou fragmento e deve apontar para
github.com/www.github.com.
O worker publica em POST /v1/projects/{REPO_PROJECT_ID}/runs usando REPO_API_TOKEN como Bearer
token. A API responde 201 para uma nova execução e 200 para uma repetição idêntica. 429,
timeouts e respostas 5xx são transitórios; erros permanentes seguem para a dead-letter queue.
Desenvolvimento
python3.13 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/ruff check .
.venv/bin/ruff format --check .
.venv/bin/mypy
.venv/bin/pytest
O CI usa Python 3.13 e executa lint, formatação, tipos, testes e build da imagem. Testes determinísticos não acessam a internet; o smoke usa uma fixture local:
docker compose run --rm smoke
Publicação no PyPI
A versão do pacote tem uma única fonte em repolens_worker/__init__.py. Antes de cada release,
atualize __version__; versões já enviadas ao PyPI não podem ser substituídas.
Para construir e validar os dois artefatos localmente:
python3.13 -m venv .venv-release
. .venv-release/bin/activate
python -m pip install --upgrade pip
python -m pip install '.[release]'
rm -rf ./build ./dist ./repolens_worker.egg-info
python -m build
python -m twine check --strict dist/*
Faça primeiro um upload de teste. O token é lido sem aparecer no histórico ou no terminal:
export TWINE_USERNAME=__token__
read -rsp 'Token do TestPyPI: ' TWINE_PASSWORD && printf '\n'
export TWINE_PASSWORD
python -m twine upload --repository testpypi dist/*
unset TWINE_PASSWORD
Depois de validar o pacote no TestPyPI, publique os mesmos artefatos no índice real com um token do PyPI:
read -rsp 'Token do PyPI: ' TWINE_PASSWORD && printf '\n'
export TWINE_PASSWORD
python -m twine upload dist/*
unset TWINE_PASSWORD TWINE_USERNAME
O workflow publish.yml é a alternativa recomendada: uma execução manual publica no TestPyPI e
uma GitHub Release publica no PyPI usando Trusted Publishing, sem armazenar token no GitHub. A
configuração inicial, validação da instalação e comandos de release estão detalhados em
docs/PUBLISHING.md.
Operação e segurança
- clone raso (
depth=1) com timeout de 120 segundos; - checkout limitado a 256 MiB e 100.000 arquivos por padrão;
- cliente HTTP sem redirects e com timeout de conexão/leitura de 5/30 segundos;
- até cinco tentativas com backoff exponencial, jitter e teto de 300 segundos;
- claims Redis por
job_ide por projeto/commit resolvido; - container não-root, filesystem raiz somente leitura e
/tmptemporário; - logs JSON correlacionados por
job_id, sem tokens ou payload completo; - métricas Prometheus de duração, destino do job e tamanho do repositório.
Repositórios privados, outros provedores Git e execução de código de terceiros permanecem fora do escopo.
Solução de problemas
Redis recusando conexão em execução local:
docker compose up -d redis
docker compose exec redis redis-cli ping
Use redis://127.0.0.1:6379/0 para processos no host e redis://redis:6379/0 dentro do Compose.
API retorna relation "projects" does not exist após usar uma configuração antiga:
docker compose up -d --force-recreate api
docker compose logs --tail=50 api
Em um ambiente local descartável, docker compose down -v recria o banco do zero, mas apaga todos
os projetos, tokens e relatórios locais.
API retorna 401 Unauthorized:
- confirme que o token foi criado para o mesmo
PROJECT_IDda URL; - exporte as variáveis antes de recriar o worker;
- gere outro token caso o valor tenha sido exposto;
- reinicie o worker após mudar credenciais.
Job não aparece na API:
docker compose logs --tail=100 worker
docker compose logs --tail=100 api
Use um job_id novo durante testes e gere a mensagem com jq para evitar JSON inválido.
Aviso de container órfão repolens-worker-dev após seguir uma versão antiga deste README:
docker rm -f repolens-worker-dev
O fluxo atual usa o serviço worker do Compose e não cria esse container nomeado.
Encerrar o ambiente
docker compose down
Para apagar também os dados locais do PostgreSQL e Redis:
docker compose down -v
Veja também SECURITY.md, docs/CONTRACT.md, docs/ADR-0001-architecture.md, docs/ADR-0002-local-integration.md e CHECKLIST.md.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file repolens_worker-0.1.0.tar.gz.
File metadata
- Download URL: repolens_worker-0.1.0.tar.gz
- Upload date:
- Size: 41.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8df34b4357f464ccc3c2d0d23529649f703aed9c58cfb6c28360cd51797ec81c
|
|
| MD5 |
982de2e30a1940689b5e43c28766b0a9
|
|
| BLAKE2b-256 |
ed4e24632d801911c88dc0389a70778e7b12af511984a14efb352cebaea9673f
|
File details
Details for the file repolens_worker-0.1.0-py3-none-any.whl.
File metadata
- Download URL: repolens_worker-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34754c875b135a626c563844768c946755e62d30b7e34c4c9695afe74a969859
|
|
| MD5 |
c41ebbbde0583c4411b6c8ee7f690320
|
|
| BLAKE2b-256 |
f929bc170ea38dccaffe701b5dab6bd9fb0fee6a02dca2e313fefa8b07621b40
|