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
onioneonion-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.yamleconfig/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_READONLYvia override noconsole.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 como0para fechar a conexão ao fim de cada request, quando o banco ainda era pequeno (spec). Em production, o valor é maior (60) comCONN_HEALTH_CHECKS=True, obrigatório porque o gunicorn usa gevent (spec)- Migrations exigem conexão que suporte DDL — pooling em modo
transactionnão suporta. Por isso o job de migrate historicamente usou conexão direta
Referências
- specs/20260711003900_migrate_staging_db_do_to_aws.md — migração para o Aurora
- specs/20260419000000_database_url_readonly_default.md — origem do contrato readonly-por-padrão
- specs/20260806102829_migrate_production_to_eks.md — production converge para o mesmo contrato
- learnings/infrastructure_pgbouncer_connection_pool.md — histórico do PgBouncer e por que ele existia