Skip to main content

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;
  • curl e jq para 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:

  1. sobe PostgreSQL, Redis e RepoLens API;
  2. aguarda o healthcheck da API;
  3. cria um projeto com credencial administrativa local;
  4. captura o project_id;
  5. cria e captura o token de ingestão, exibido apenas uma vez pela API;
  6. salva as credenciais em .env.local com permissão restrita;
  7. inicia o serviço worker normal do Compose;
  8. enfileira https://github.com/Jonatanjrss/repolens-core;
  9. 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_id e por projeto/commit resolvido;
  • container não-root, filesystem raiz somente leitura e /tmp temporá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_ID da 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

repolens_worker-0.1.0.tar.gz (41.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

repolens_worker-0.1.0-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

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

Hashes for repolens_worker-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8df34b4357f464ccc3c2d0d23529649f703aed9c58cfb6c28360cd51797ec81c
MD5 982de2e30a1940689b5e43c28766b0a9
BLAKE2b-256 ed4e24632d801911c88dc0389a70778e7b12af511984a14efb352cebaea9673f

See more details on using hashes here.

File details

Details for the file repolens_worker-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for repolens_worker-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 34754c875b135a626c563844768c946755e62d30b7e34c4c9695afe74a969859
MD5 c41ebbbde0583c4411b6c8ee7f690320
BLAKE2b-256 f929bc170ea38dccaffe701b5dab6bd9fb0fee6a02dca2e313fefa8b07621b40

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page