Engenharia & Método · 7 min
Uma otimização de performance tirou o próprio site do ar. Duas vezes.
Ativamos cache de borda para acelerar o carregamento das páginas. O resultado foi uma página de produção respondendo erro 500, de forma persistente, sem nunca servir a versão cacheada. A causa raiz levou mais de uma semana para ficar clara.
Por Diogo Kammers · 17/09/2026
O plano parecia simples
Este site roda em Cloudflare Workers. Uma das recomendações mais comuns de performance para esse tipo de arquitetura é usar cache de borda: guardar a resposta HTML de uma página perto do visitante, para que a segunda pessoa que acessa a mesma URL não espere o servidor renderizar tudo de novo. Implementamos isso como parte de uma rodada de otimizações de performance, com cuidado explícito para excluir páginas sensíveis (área administrativa, login, resultados individuais de pesquisa e diagnóstico) do que poderia ser cacheado.
A primeira versão usava um header HTTP padrão, CDN-Cache-Control, que o Cloudflare reconhece em teoria. Publicamos, e nada quebrou de imediato.
O primeiro sinal de que algo estava errado
Depois do publish, checamos se o cache estava funcionando de verdade. curl repetido na mesma URL nunca trouxe o cabeçalho cf-cache-status que indicaria um acerto de cache. Nenhuma vez, em várias tentativas. A explicação, descoberta só nesse ponto: Workers publicados em domínio customizado (não no subdomínio padrão da Cloudflare) não cacheiam automaticamente por header HTTP. É preciso usar a Cache API do próprio Workers, de forma explícita, no código.
Reescrevemos a lógica: no início de cada requisição, uma rota elegível tenta buscar a resposta no cache antes de qualquer outra coisa. Se encontrar, devolve direto, sem tocar em banco de dados. Se não encontrar, segue o fluxo normal e, ao final, guarda uma cópia da resposta para a próxima vez, sem atrasar a resposta ao usuário atual.
A página que devia acelerar parou de responder
Logo depois desse ajuste ir ao ar, a página /recursos/faq começou a responder erro 500 de forma persistente. Cinco requisições seguidas, todas com o mesmo erro, nenhuma delas com sinal de ter vindo do cache. A mitigação imediata foi zerar a lista de rotas elegíveis para cache, voltando o site ao normal enquanto a causa raiz era investigada sem a pressão de produção fora do ar.
A investigação que seguiu não encontrou uma resposta limpa. Tentamos reproduzir o erro localmente, rodando o mesmo ambiente de produção (o mesmo runtime que o Cloudflare usa, não um substituto), inclusive sob dez requisições simultâneas. Sempre 200. Nunca reproduzimos o 500 fora de produção.
Um fato novo apareceu na investigação: o código publicado de verdade usava um caminho de execução ligeiramente diferente do que o comentário no próprio arquivo descrevia, e a função que conectava a rota ao restante do sistema não repassava dois parâmetros que o código assumia estarem sempre presentes. Corrigimos essa divergência e adicionamos tratamento de erro explícito nos dois pontos do fluxo de cache que não tinham: a leitura do cache e a gravação. Nenhum dos dois lançava exceção de forma síncrona antes dessa correção. Se qualquer um dos dois falhasse na borda real, o sintoma seria exatamente o observado: erro sem nunca servir a versão em cache.
A decisão que importa mais que a correção
O ponto mais relevante deste incidente é que a causa raiz nunca foi confirmada com certeza absoluta, mais do que o bug em si. Não foi possível reproduzir o comportamento exato de produção fora dela, porque partes do ambiente real (a Cache API da borda de verdade, a conta de infraestrutura específica) não são replicáveis localmente.
Diante disso, a decisão foi manter a lista de rotas cacheáveis vazia mesmo depois de aplicar as correções mais prováveis. Reativar o cache de borda continua dependendo de confirmação em produção, sob monitoramento, e não da confiança de que o problema "provavelmente" foi resolvido. Corrigir às cegas, sem poder confirmar, teria sido o mesmo tipo de aposta que causou o problema na primeira vez.
Como confirmar que o cache está funcionando de verdade
Com a Cache API explícita do Workers, o cabeçalho cf-cache-status que normalmente indica acerto de cache no Cloudflare não aparece nas respostas, porque não é mais o cache automático da Cloudflare respondendo. A forma de confirmar que o cache está funcionando passou a ser outra: medir o tempo de resposta de duas chamadas seguidas à mesma URL elegível. A segunda, servida do cache, precisa ser visivelmente mais rápida que a primeira. Um detalhe pequeno, mas que muda completamente como se lê "funcionou" nesse tipo de arquitetura: não é a ausência de erro, é uma diferença de tempo mensurável.
Esse mesmo cuidado apareceu numa segunda frente da mesma rodada de otimizações, que foi deliberadamente abandonada: uma métrica de estabilidade visual estava alta numa página específica, e duas hipóteses pareciam prováveis (troca de fonte web, custo de hidratação proporcional ao tamanho da página). Nenhuma das duas foi corrigida, porque nenhuma podia ser confirmada sem uma medição de antes e depois que não havia como rodar naquele momento. Implementar uma correção às cegas ali teria sido o mesmo erro que o cache de borda cometeu, só que na direção contrária: mexer sem poder provar que a mudança ajudou.
O que ficou como prática
A lição que ficou vai além de cache HTTP: é sobre o que fazer quando a causa raiz de um incidente em produção não pode ser provada com a mesma certeza que corrigiu o sintoma. Aplicar uma correção provável e seguir em frente é diferente de aplicar uma correção provável e continuar tratando o raio de exposição como fechado até a prova chegar.
Veja as outras peças desta série, sobre incidentes reais e o que cada um ensinou: uma migração de banco que estourou o tempo limite do Postgres, uma calculadora que recusava toda execução em silêncio, e o guardrail que nasceu de um git add -A que misturou o trabalho de duas sessões.
Esse artigo faz parte do hub Engenharia & Método.