Problema
Cache “para ficar rápido” sem política de invalidação vira dados fantasmas após deploy ou mutação. Chaves colidem entre ambientes; TTL infinito esconde bugs.
Solução
Definir padrão de chave (env:tenant:resource:id), TTL por tipo de dado e estratégia: cache-aside para leitura dominante; write-through onde stale é inaceitável; bust por tag/evento quando possível.
Arquitetura
Request → handler → (1) tenta Redis GET
→ (2) miss → DB → SET com TTL
Mutation → atualiza DB → DEL ou INCR versão da chave agrupada
- Stampede: singleflight ou lock leve em miss quente.
- Circuit breaker se Redis estiver instável — degradar para origin com limite.
Código
async function getUserCached(id: string) {
const key = `prod:user:${id}`;
const hit = await redis.get(key);
if (hit) return JSON.parse(hit);
const user = await userRepo.findById(id);
if (!user) return null;
await redis.set(key, JSON.stringify(user), "EX", 300);
return user;
}
export async function updateUser(id: string, patch: Patch) {
await userRepo.update(id, patch);
await redis.del(`prod:user:${id}`);
}Performance
Pipeline de comandos; serialização compacta (msgpack) para payloads grandes; não cachear objetos sensíveis sem criptografia em repouso.
Melhorias futuras
Redis Cluster; near-cache em processo para leituras extremamente quentes; métricas hit ratio.
Conclusão
Cache é feature de consistência disfarçada. Mostrar que você pensa em invalidação prova maturidade de escala.