Contrato do DATABASE_URL

TLDR: A aplicação sempre lê DATABASE_URL. A infra decide se essa URL aponta para uma conexão readonly ou de escrita total — a aplicação nunca sabe a diferença.

Nota de reconstrução: o documento original descrevia o banco quando era PostgreSQL gerenciado da DigitalOcean atrás de PgBouncer (portas 25060/25061, pools onion e onion-readonly). Staging migrou para Aurora Serverless v2 em julho/2026 e esses pools não existem mais. O conteúdo abaixo foi reconstruído a partir de .infra/terraform/secrets.tf, .infra/k8s/base/specs/*-deployment.yaml e config/settings/base.py — daí certainty: medium. Os comandos de acesso vêm do documento original e não foram reverificados.

Visão geral

A aplicação lê uma única variável, DATABASE_URL (config/settings/base.py). Quem decide o que ela contém é o entrypoint do commons, em runtime, a partir de dois secrets injetados pelo Terraform.

Contratos

Chaves no secret do k8s

O secret onion-backend-secrets (criado por .infra/terraform/secrets.tf) carrega:

Chave Aponta para Propósito
DATABASE_URL_READONLY endpoint reader do cluster Aurora Queries de leitura
DATABASE_URL_FULLACCESS endpoint writer do cluster Aurora Queries de leitura e escrita

Ambas são connection strings PostgreSQL na porta padrão do cluster (5432), com ?sslmode=require. Não há mais camada de pooling externa (PgBouncer) entre a aplicação e o banco — o Aurora atende diretamente.

Os deployments web, worker e worker-habits recebem as duas chaves; o migrate-job também.

Comportamento em runtime

O entrypoint do commons (/usr/local/bin/entrypoint) roda antes de cada container:

  • Pods de runtime (web, worker, beat): recebem os dois secrets. O entrypoint define DATABASE_URL=$DATABASE_URL_FULLACCESS. Loga em laranja: [db] full access
  • Pods de console/shell: recebem apenas DATABASE_URL_READONLY via override no console.sh. O entrypoint loga em ciano: [db] readonly mode

Comandos de acesso

Comando Acesso ao banco
mk console.staging readonly
mk shell.staging readonly
mk console.staging.admin full access
shell via k9s em pod rodando full access

Pressão de conexões

O Aurora Serverless v2 escala capacidade, mas o número de conexões continua sendo um recurso finito. Dois controles importam:

  • CONN_MAX_AGE — em staging foi definido como 0 para fechar a conexão ao fim de cada request, quando o banco ainda era pequeno (spec). Em production, o valor é maior (60) com CONN_HEALTH_CHECKS=True, obrigatório porque o gunicorn usa gevent (spec)
  • Migrations exigem conexão que suporte DDL — pooling em modo transaction não suporta. Por isso o job de migrate historicamente usou conexão direta

Referências