Cache strategy (não-técnico)
Esta página explica, sem assumir conhecimento de Cloudflare, Workers ou caching, como o cache funciona na plataforma e o que esperar quando algo muda em produção.
Para o lado técnico (APIs, arquivos, fluxos de dados), veja Cache architecture. Para "como faço pra forçar X agora", veja Cache operations.
TL;DR (pra quem tem 30 segundos)
- A plataforma guarda cópias temporárias das respostas do BFF em vários lugares ("cache") pra abrir página rápido.
- Cada tipo de dado tem um prazo de validade (TTL). Quando vence, a próxima visita busca dado fresco.
- O TTL do brandConfig (a maioria do que muda no backoffice) é 1 minuto. Tudo mais novo entra automaticamente em até 1min sem ninguém precisar fazer nada.
- Pra coisas que não são brandConfig (catálogo de jogos, top wins, etc) o TTL é mais longo. Quando precisa atualizar fora desse prazo, alguém roda um workflow no GitHub Actions (
Manual Cache Purge) e o cache é zerado. - Tem 5 camadas de cache no caminho — não uma só. O workflow de purge sabe atualizar quatro delas em uma operação só. A quinta vive dentro do browser do usuário (Service Worker) e nenhum purge do servidor alcança — ela se renova sozinha a cada deploy.
Por que precisa de cache?
A plataforma serve dezenas de milhões de páginas por dia. Cada uma envolve dezenas de chamadas ao backend (config da marca, catálogo de jogos, estatísticas, banners, traduções, payment-providers...). Se cada visitante batesse no BFF (o backend principal) pra renderizar a home, o backend cairia em minutos.
A solução é guardar a resposta a primeira vez que ela é calculada, e servir de cópia local nas próximas visitas — até a cópia ficar "velha demais". Esse "velha demais" é o que a gente chama de TTL (Time To Live).
Como uma página vira lenta sem cache?
Pra renderizar a home anonima, o navegador pede o HTML. O servidor precisa:
- Saber qual brand é (
brandConfig— banners, cores, features, idioma) - Saber quais jogos mostrar (catálogo, "top wins", "high payers")
- Saber o usuário (se logado)
- Buscar promos ativas
- Aplicar overrides do brand
- Renderizar o HTML
- Mandar de volta
Cada item tem uma ou mais chamadas ao BFF. Sem cache:
- ~10 chamadas BFF por requisição
- Cada uma tem ~150-400ms de latência (CDN → BFF → DB → volta)
- Total: 2-4 segundos por página
- Multiplica isso por milhares de visitas/minuto → BFF não aguenta
Com cache:
- 1ª visita: paga o custo (2-4s)
- Próximas N visitas: lê do cache em ~10ms
- BFF só vê 1 chamada a cada TTL minutos, não N
Resultado: mesma página em ~200ms, BFF tranquilo.
As 5 camadas em uma analogia
Imagine que você trabalha numa loja física com 5 funcionários em sequência. Cliente entra na porta principal:
- Caderninho do cliente (Service Worker, no browser dele) — o cliente anotou a página inteira da última visita. Se a anotação ainda está no prazo, ele nem entra na loja. Ninguém dentro da loja consegue rasgar esse caderninho: ele se troca sozinho quando sai uma versão nova do site (deploy).
- Porteiro (CF Zone Edge) — guarda HTMLs prontos pra páginas anônimas. Se já viu a página, entrega na hora sem incomodar ninguém.
- Recepcionista (Brand Worker — middleware) — guarda o HTML já renderizado da página (uma gaveta pra visitante anônimo, outra pra cada sessão logada).
- Gerente (platform-cache engine) — coordena as respostas lógicas grandes ("dados da home", "config da marca"). Se já tem na pasta, devolve. Se a pasta tá velha, devolve a cópia velha rapidinho e já manda buscar a nova em segundo plano.
- Estagiário (front-service-api proxy) — fica em Frankfurt (perto do BFF). Quando o gerente realmente precisa pedir pro BFF, o estagiário vai correndo, traz a resposta e ainda guarda cópia local pra próxima.
(Existe ainda um bloco de notas menor no browser — localStorage do api-client,
1 min — que o logout limpa.)
Cada um tem prazo de validade próprio nas cópias dele. Quando todos topam que "tá velho", o caminho completo é refeito.
:::info O que mudou em 2026-07
A "recepcionista" antes também guardava respostas de API numa gaveta própria.
Essa gaveta foi removida: ela duplicava os prazos do estagiário e era causa
de dado velho. Hoje cache de API tem um dono só — o estagiário
(front-service-api).
:::
Os tipos de dados e seus prazos
Os principais tipos cacheados, com seus TTLs em produção:
| O que é | TTL | Reflete em backoffice em |
|---|---|---|
| Config da marca (banners, cores, features, payment-providers list) | 1 min | até 1min |
| Rows de home / cassino / live | 1h | até 1h ou purge manual |
| Catálogo de jogos (lista, categorias, providers) | 1h | até 1h ou purge manual |
| Detalhes de jogo individual | 1h | até 1h ou purge manual |
| Estatísticas (top wins, last wins, stats por jogo) | 30 min | até 30min ou purge manual |
| Wins por jogo / página de listagem filtrada | 5 min | até 5min |
| Conteúdo (CMS) | 5-10 min | até 10min |
| Termos legais | 1h | até 1h |
| Sitemap | 1h | até 1h |
"Reflete em backoffice em" = quanto tempo entre alguém salvar uma mudança no backoffice e essa mudança aparecer no site sem que ninguém faça nada.
Esta tabela é um resumo. Os valores por resource vivem em
front-ops/config/cache/defaults.yml— é lá que se confere o número exato.
Como "puxa atualização" sem esperar o TTL
Quando alguém precisa que uma mudança apareça agora (mudança crítica no backoffice, fix emergencial), o caminho é:
- Vai no repositório
front-opsno GitHub - Actions → "Manual Cache Purge"
- Preenche:
- environment: a brand/env (ex:
prod-7k-bet-br,betpontobet-bet-br) — a lista viva está emfront-ops/config/brands/*/environments/ - tags: o tipo do dado a invalidar (ex:
brandpra config,catalogpra jogos,paymentspra pagamentos) - ou glob: padrão como
games:*pra tudo que envolve jogos
- environment: a brand/env (ex:
- Run workflow
- Em 30s o cache foi limpo, próxima visita pega dado fresco
Não precisa fazer deploy. Purge é independente do código.
Quando deploy também atualiza cache?
Todo deploy inclui um purge automático — mas ele é condicional, não incondicional:
- O deploy gera um novo
BUILD_ID(identificador único do deploy) - Esse ID é usado como "etiqueta" em várias camadas de cache → cópias antigas viram órfãs e expiram
- Logo após o deploy, o workflow dispara purge automático pros principais resources se e somente se
CACHE_PURGE_SECRETestiver configurado na brand/env. Se o secret não estiver setado, o step é pulado com aviso — não falha o deploy. - O purge da plataforma (platform-cache) agora falha o deploy se retornar non-2xx. O purge do SSR/zone continua sendo aviso-only (não bloqueia).
- E faz um "warm-up": curl em 10 páginas-chave pra repopular o cache antes do tráfego real chegar
Isso vale pra deploy.yml do brand worker. O front-service-api é deployado separadamente.
Importante: um novo resource no
front-ops/config/cache/defaults.ymlnão é ativado automaticamente quando ofront-opsfaz push. Ele precisa de um redeploy explícito do brand worker (o worker lê a policy em deploy-time via--var PLATFORM_CACHE_POLICY_JSON).
Tipos de problemas e o que fazer
"Mudei algo no backoffice e não vejo no site"
Provavelmente é brandConfig. Aguarde 1min. Se não voltar:
- Confirma se a mudança foi salva no backoffice e se aparece no
/api/dev/cache-policyda brand. - Roda
manual-cache-purge.ymlcomtags: brandna env correspondente. - Se ainda persistir, é provavelmente cache do navegador — e nesse caso é quase sempre o Service Worker, não o HTTP cache. Ctrl+Shift+R não basta: teste em janela anônima, ou abra a URL com
?version=2(bypass da chave do SW). Ver Service Worker.
"Adicionei um jogo novo e não aparece"
Catálogo tem TTL 1-2h. Pra forçar:
- Roda
manual-cache-purge.ymlcomtags: catalogna env (ouglob: games:*).
"Banner velho aparecendo em uma região mas não em outra"
Cache no Cloudflare é por DC (datacenter). Pode estar warm em um, frio em outro. Soluções:
- Roda
manual-cache-purge.ymlcomscope: zone(purge global na zona CF). - Ou aguarda — TTL do brandConfig é 1min, vai sincronizar.
"Site inteiro carregando dados velhos"
Cenário raro mas existe. Roda manual-cache-purge.yml com:
- environment correta
- (deixa tudo vazio = purgeAll)
- scope: all
- Vai limpar tudo: brand worker, service-api e zone CF.
"Um usuário vê a página velha mesmo depois do deploy"
Purgamos tudo no servidor e ele continua vendo o HTML antigo? Provavelmente é o Service Worker — a cópia está no browser dele, e nenhum purge do servidor chega lá. Diagnóstico e escape hatches em Service Worker.
Atalho pra desbloquear uma pessoa na hora: peça pra abrir a URL com
?version=2. É o bypass de chave do SW — força uma entrada nova sem mexer em
nada no servidor.
"Aconteceu uma falha no BFF e quero saber se o site vai ficar OK"
Sim, há proteção. O platform-cache tem staleIfError: se o BFF cair, ele continua servindo a última cópia conhecida. A janela padrão é 6h (staleIfErrorSeconds: 21600), mas não é universal — topWins/lastWins/gameTopWins usam 30min e gameDetail/allGames/gameCategory/gameProvider usam 2h. Os valores por resource estão em front-ops/config/cache/defaults.yml. E se nem isso tem, busca do KV snapshot global. Site não fica branco.
Quando NÃO usar purge?
- Não tenta "limpar todo cache pra ver se resolve um bug do código". Cache não causa bugs de lógica, ele só atrasa atualizações. Bug é bug, vai aparecer depois também.
- Não roda purge a cada 5 min "preventivamente". Anula o ponto do cache. Confia nos TTLs.
- Não usa
scope: zonecasualmente. É operação cara (custo CF) e nuclear (afeta todos os arquivos cacheados, incluindo assets imutáveis). Use só quando realmente precisa.
Quem é dono do quê?
| Camada | Owner | Como mexer |
|---|---|---|
| Service Worker (browser) | Dev (código) | Rotaciona por BUILD_ID a cada deploy. Purge de servidor não alcança · Service Worker |
| CF Zone Edge | DevOps | Dashboard CF ou manual-cache-purge.yml scope: zone |
| Brand worker SSR cache | Dev (auto via deploy) | Bump de BUILD_ID = invalidação · TTL por env (SSR_CACHE_HTML_TTL) |
| platform-cache engine | Dev (policy) + DevOps (purge runtime) | Policy: front-ops/config/cache/defaults.yml · Purge: manual-cache-purge.yml |
| service-api proxy | Dev (rules) + DevOps (purge runtime) | Rules: front-ops/config/cache/service-api-defaults.yml · Purge: cascateado pelo brand worker |
| Browser localStorage | usuário | Logout limpa caches do api-client |
Glossário
- TTL (Time To Live) — quanto tempo a cópia em cache é considerada "fresca". Após o TTL, vira "stale" (velha).
- SWR (Stale While Revalidate) — período extra depois do TTL onde a cópia velha ainda pode ser servida, enquanto uma cópia nova é buscada em segundo plano. Visitante sempre tem resposta rápida.
- Stale-if-Error — período extra onde a cópia velha pode ser servida se o BFF tá fora do ar (graceful degradation).
- Purge — apagar manualmente do cache (sem esperar TTL).
- BUILD_ID — identificador único do deploy. Usado como etiqueta em namespaces de cache → todo deploy "invalida via namespace".
- Resource — uma unidade lógica de dado cacheada (
brandConfig,homeRows, etc). - Tag — palavra-chave declarada num resource (
brand,catalog,games:list). Permite purges agrupados. - KV — armazenamento global da Cloudflare, cross-DC. Usado como fallback estável para resources críticos.
- Cache API — o cache de edge da Cloudflare, por datacenter. Mais rápido que KV mas não cross-DC.