Pular para o conteúdo principal

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:

  1. Saber qual brand é (brandConfig — banners, cores, features, idioma)
  2. Saber quais jogos mostrar (catálogo, "top wins", "high payers")
  3. Saber o usuário (se logado)
  4. Buscar promos ativas
  5. Aplicar overrides do brand
  6. Renderizar o HTML
  7. 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:

  1. 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).
  2. 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.
  3. Recepcionista (Brand Worker — middleware) — guarda o HTML já renderizado da página (uma gaveta pra visitante anônimo, outra pra cada sessão logada).
  4. 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.
  5. 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 éTTLReflete em backoffice em
Config da marca (banners, cores, features, payment-providers list)1 minaté 1min
Rows de home / cassino / live1haté 1h ou purge manual
Catálogo de jogos (lista, categorias, providers)1haté 1h ou purge manual
Detalhes de jogo individual1haté 1h ou purge manual
Estatísticas (top wins, last wins, stats por jogo)30 minaté 30min ou purge manual
Wins por jogo / página de listagem filtrada5 minaté 5min
Conteúdo (CMS)5-10 minaté 10min
Termos legais1haté 1h
Sitemap1haté 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 é:

  1. Vai no repositório front-ops no GitHub
  2. Actions → "Manual Cache Purge"
  3. Preenche:
    • environment: a brand/env (ex: prod-7k-bet-br, betpontobet-bet-br) — a lista viva está em front-ops/config/brands/*/environments/
    • tags: o tipo do dado a invalidar (ex: brand pra config, catalog pra jogos, payments pra pagamentos)
    • ou glob: padrão como games:* pra tudo que envolve jogos
  4. Run workflow
  5. 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:

  1. O deploy gera um novo BUILD_ID (identificador único do deploy)
  2. Esse ID é usado como "etiqueta" em várias camadas de cache → cópias antigas viram órfãs e expiram
  3. Logo após o deploy, o workflow dispara purge automático pros principais resources se e somente se CACHE_PURGE_SECRET estiver configurado na brand/env. Se o secret não estiver setado, o step é pulado com aviso — não falha o deploy.
  4. 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).
  5. 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.yml não é ativado automaticamente quando o front-ops faz 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:

  1. Confirma se a mudança foi salva no backoffice e se aparece no /api/dev/cache-policy da brand.
  2. Roda manual-cache-purge.yml com tags: brand na env correspondente.
  3. 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:

  1. Roda manual-cache-purge.yml com tags: catalog na env (ou glob: games:*).

Cache no Cloudflare é por DC (datacenter). Pode estar warm em um, frio em outro. Soluções:

  1. Roda manual-cache-purge.yml com scope: zone (purge global na zona CF).
  2. 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: zone casualmente. É 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ê?

CamadaOwnerComo 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 EdgeDevOpsDashboard CF ou manual-cache-purge.yml scope: zone
Brand worker SSR cacheDev (auto via deploy)Bump de BUILD_ID = invalidação · TTL por env (SSR_CACHE_HTML_TTL)
platform-cache engineDev (policy) + DevOps (purge runtime)Policy: front-ops/config/cache/defaults.yml · Purge: manual-cache-purge.yml
service-api proxyDev (rules) + DevOps (purge runtime)Rules: front-ops/config/cache/service-api-defaults.yml · Purge: cascateado pelo brand worker
Browser localStorageusuárioLogout 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.