Cortando segundos de latência com um cache que não existia de verdade
· 6 min
Um backend rodando em ambiente serverless, com um banco de dados compatível com SQLite na borda, tinha um punhado de endpoints consistentemente lentos, não sob pico de tráfego, mas mesmo em uso normal, com uma única requisição isolada. A lógica de negócio por trás deles era simples; nada explicava a demora.

Rastreando a lentidão até a camada de dados
Os logs mostravam que o tempo não estava nas rotas nem no motor do banco em si, mas em algo que acontecia antes de qualquer query útil rodar. Toda a aplicação passava por um container de dependências que montava mais de dez repositórios a cada requisição, e cada repositório, ao ser instanciado, tinha um método de inicialização de schema que deveria rodar só uma vez por processo.
O cache que existia no papel, mas não no código
O mecanismo pra evitar esse trabalho repetido já estava desenhado: cada repositório guardava uma referência pensada pra funcionar como cache do estado "schema já validado". O problema é que essa referência nunca era de fato lida nem preenchida, existia como campo, mas nada no fluxo verificava seu valor antes de repetir o trabalho. Na prática, isso equivalia a não ter cache nenhum: toda requisição recriava o container inteiro e, pra cada um dos repositórios, refazia checagens e ajustes de schema, CREATE TABLE, checagem de colunas, alterações condicionais, criação de índice, mesmo num processo já aquecido, que tinha acabado de fazer exatamente o mesmo trabalho na requisição anterior.
A correção: fazer o cache funcionar de verdade
A correção não foi arquitetural, foi fazer o mecanismo de cache que já existia realmente funcionar: preencher e checar aquela referência de estado por repositório, pra que a validação de schema só rodasse na primeira vez que o processo lidava com ele, e guardar a instância do container de dependências em escopo de módulo em vez de recriá-la a cada chamada. A mudança foi aplicada de forma uniforme em todos os repositórios do sistema, não só nos que tinham sido identificados como lentos, evitando deixar o mesmo problema latente em outro lugar.
Resultado
As requisições que antes chegavam a levar segundos por causa desse trabalho repetido passaram a responder em poucos milissegundos, sem nenhuma mudança de infraestrutura, só fazendo o cache que já estava desenhado no código funcionar como deveria desde o início.