Blog

Acordar bancos de dados sem conexões mortas

Os apps publicados no Mythex, e os bancos de dados deles, entram em repouso quando ninguém os usa. Quando um app acordava, podia segurar a primeira requisição por 10 a 12 segundos, porque tentava reutilizar conexões com o banco de dados que tinham morrido enquanto tudo dormia. Agora damos aos apps Spring Boot configurações de banco seguras através do repouso, e pedimos ao agente que construa apps de qualquer stack do mesmo jeito. Na plataforma de hospedagem, a primeira requisição depois de acordar caiu de 12,7 segundos para 2,3 segundos.

Por que apps e bancos dormem

Um app publicado no Mythex roda em uma máquina que é suspensa após alguns minutos ociosa, e o banco de dados dele é um Postgres serverless que entra em repouso após cinco minutos ociosos e acorda na próxima requisição. É isso que mantém barato um app tranquilo: você paga pelo que o banco realmente usou, e um app em repouso não gasta nada com computação. Escrevemos sobre o lado da cobrança em cobrança de bancos de dados pelo que eles realmente usam.

O porém é que os dois dormem separadamente e não concordam sobre o que é uma conexão.

O sintoma: uma primeira visita lenta

A maioria dos apps de servidor mantém um pool de conexões: um punhado de conexões abertas com o banco, prontas, para que cada requisição não precise pagar o custo de abrir uma nova. É o desenho certo para um app sempre ligado.

Eis o que acontece com o repouso:

  1. O app está rodando, com algumas conexões ociosas no pool.
  2. Ninguém visita. A máquina do app é suspensa, congelada, com o pool intacto.
  3. O banco entra em repouso e derruba a sua ponta de cada conexão.
  4. Um visitante chega. O app acorda exatamente como estava, ainda segurando conexões que o banco não conhece mais.
  5. O pool entrega uma dessas conexões. Ele precisa descobrir que ela morreu, tentando usá-la e esperando, antes de desistir dela.

Em um app Spring Boot, validar essas conexões mortas bloqueava a primeira requisição por cerca de 10 segundos, até que ela falhasse com "Connection is not available". Para o visitante, o site simplesmente travava, e às vezes mostrava um erro.

Por que os apps Spring foram os mais afetados

Spring Boot é um framework Java popular, e usa por padrão um pool de conexões chamado HikariCP. O Spring pode configurar esse pool por meio de configurações, incluindo quantas conexões ociosas manter.

Mas o Mythex entrega o banco de cada app como uma única DATABASE_URL no formato postgresql://user:pass@host/db. O Spring não consegue ler esse formato diretamente. Então os apps Spring construídos no Mythex montavam o próprio pool no código, analisando essa URL, e um pool montado à mão ignora todas as configurações spring.datasource.* do Spring. Mesmo que alguém soubesse as configurações certas do pool, não havia lugar onde elas fariam efeito.

A correção, parte 1: configurações que o Spring pode usar

Quando um projeto tem um banco de dados, agora também recebe variáveis de ambiente que o Spring lê nativamente:

  • SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME e SPRING_DATASOURCE_PASSWORD, convertidas a partir de DATABASE_URL (com SSL obrigatório, a menos que a URL diga o contrário).
  • Configurações do pool que sobrevivem ao repouso:
ConfiguraçãoValorPor quê
Mínimo de conexões ociosas0Não manter nada aberto entre requisições, para que não haja nada que fique desatualizado
Tempo limite de ociosidade30 segundosFechar conexões não usadas logo
Tempo de vida máximo2 minutosAposentar toda conexão antes que ela envelheça
Tempo limite de conexão5 segundosNão prender uma requisição por muito tempo se o banco demorar a responder

Sem conexões ociosas mantidas, um app acordado abre uma conexão nova em vez de vadear por conexões mortas.

Com essas variáveis presentes, o Spring configura o próprio pool, e as configurações valem. O que o projeto já tiver definido sempre prevalece; nós só preenchemos o que falta. Apps que não são Spring ignoram essas variáveis.

O detalhe que quase fez tudo não funcionar

O Spring mapeia variáveis de ambiente para as suas configurações por uma regra fácil de errar. A configuração minimum-idle precisa ser escrita como SPRING_DATASOURCE_HIKARI_MINIMUMIDLE: sem traços, com as palavras juntas. Escrevê-la como SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, que parece mais natural, aponta para outra configuração que não existe (minimum.idle) e é ignorada sem aviso.

Esse é o tipo de erro que passa em todas as revisões e não faz nada em produção. Por isso, um teste verifica tanto que os valores estão definidos quanto que nenhuma variável usa a forma separada por sublinhado.

A correção, parte 2: todas as outras stacks

Spring não é o único framework com pool, e não dá para pré-configurar todas as bibliotecas de todas as linguagens. Então o agente do Mythex, a IA que escreve o seu app, agora recebe uma instrução permanente para qualquer stack: apps publicados e os bancos deles entram em repouso quando ociosos, então uma conexão mantida aberta pode estar morta na requisição seguinte. Ele deve:

  • não manter conexões de banco ociosas abertas, ou verificar cada uma antes de usar,
  • tentar de novo uma vez em caso de erro de conexão, e
  • usar as configurações de banco que a plataforma fornece no ambiente, em vez de montar o próprio pool analisando DATABASE_URL.

Esse último ponto fecha o ciclo com a parte 1: um app construído sobre as configurações fornecidas recebe automaticamente a configuração segura para o repouso.

O resultado

Medido na plataforma de hospedagem onde rodamos os apps publicados, a primeira requisição depois de acordar caiu de 12,7 segundos para 2,3 segundos.

O que tiramos disso

  • Toda camada que entra em repouso precisa concordar sobre o que sobrevive. Uma máquina congelada e um banco em repouso fizeram, cada um, uma escolha razoável. Juntos, o app acordou segurando um estado que já não era verdadeiro.
  • Padrões pensados para servidores sempre ligados não servem para apps que escalam até zero. Manter conexões aquecidas é uma boa ideia até que tudo ao redor esfrie.
  • Entregue aos frameworks os dados no formato deles. Uma URL única era simples para nós, mas obrigava todo app Spring a montar um pool à mão que ignorava a própria configuração.
  • Teste se uma configuração está escrita do jeito que o framework a lê. Um valor correto com o nome errado não faz nada, e não avisa.

Se você é novo em como os bancos funcionam no Mythex, veja a documentação do banco de dados e nosso texto explicativo sobre o que é o Postgres.

Mythex · Pricing · Crie qualquer coisa com IA · Templates de sites e apps · Mythex comparado · Glossário de criação de apps com IA · Ferramentas grátis para criar apps com IA · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)