Pular para o conteúdo principal

Cache operations (playbooks)

Esta página é o manual de operações pro cache da plataforma. Cada seção é um playbook independente — entrar, fazer, sair.

Para entender por que o sistema é assim, veja Cache architecture. Para a visão de "como funciona, sem detalhes técnicos", veja Cache strategy.

Pré-requisitos

  • Acesso ao repositório cactus-agents/front-ops no GitHub
  • Permissão pra rodar Actions workflows
  • Em casos críticos: acesso ao Cloudflare Dashboard (CT e/ou BT)

Todos os exemplos abaixo assumem vera-bet-br como brand/environment. Substitua pelo seu caso.


Playbook 1 — Invalidar config de brand (banners, payment-providers)

Quando usar: mudança no backoffice (banner novo, ordem de payment-providers, feature flag) que não está aparecendo após 1-2min.

Tempo: ~30s.

Passos:

  1. GitHub → cactus-agents/front-ops → Actions → Manual Cache Purge → Run workflow
  2. Inputs:
    • environment: vera-bet-br (ou prod-7k-bet-br, etc)
    • tags: brand
    • scope: all (purga platform-cache + service-api)
  3. Run
  4. Aguarda ~30s. O step summary mostra resposta de cada camada.
  5. Valida visitando o site em janela anônima (pra contornar browser cache).

O que acontece por trás:

  • Brand worker engine.purgeByTag("brand") invalida brandConfig (e qualquer outro resource com tag brand)
  • Cascade pro service-api purga entradas com tag brand (/v2/bff/features, /v2/appearance, /v2/bookmaker-settings, /v2/configurations/casino, /v2/country)
  • Próxima request → BFF → dado fresco

Por que isso é suficiente:

  • TTL do brandConfig é 60s; este purge é só pra forçar antes do TTL natural expirar
  • Não precisa zone purge nem CF Cache Reserve

Playbook 2 — Invalidar catálogo de jogos

Quando usar: jogo novo adicionado, jogo removido, mudança de ordem em categorias.

Tempo: ~30s.

Passos:

  1. Actions → Manual Cache Purge → Run workflow
  2. Inputs:
    • environment: vera-bet-br
    • glob: games:* (cobre games:list, games:detail, games:wins, games:stats, games:high-payers, games:category, games:provider, games:base, games:listPage, games:all)
    • scope: all
  3. Run.

Variante (mais cirúrgica):

Pra atingir só home + casino (não detalhe de jogo):

  • tags: rows
  • scope: all

Pra atingir só a estatística "pagou hoje":

  • tags: stats
  • scope: all

Playbook 3 — "O site inteiro tá com dados velhos, quero zerar tudo"

Quando usar: ultima opção. Postmortem em andamento, problema generalizado, ou após uma mudança grande no BFF.

Tempo: ~1-2min (incluindo zone purge).

Passos:

  1. Actions → Manual Cache Purge → Run workflow
  2. Inputs:
    • environment: vera-bet-br
    • (deixa tags/glob/segments vazios) = purgeAll
    • scope: all
  3. Run.

O que acontece:

  • platform-cache engine.purgeAll() no brand worker
  • service-api purga TODAS as entries com originDomain: vera.bet.br ({ all: false, originDomain: "vera.bet.br" })
  • CF zone purge_everything (apaga TODO o cache de zone — assets, HTMLs, .data)

Cuidado: zone purge_everything tem custo CF e é nuclear. Use só quando realmente necessário.


Playbook 4 — Invalidar só uma camada (debug)

Quando usar: investigando se um problema específico está em uma camada ou outra.

Inputs:

  • scope: platform-cache — só invalida no brand worker (memory + CF Cache API + KV snapshot do platform-cache)
  • scope: service-api — só invalida no proxy worker (KV API_CACHE_KV + CF Cache API do service-api)
  • scope: zone — só CF zone purge (edge cache do SSR HTML)

Use cases típicos:

  • "Dados que vêm da home tão velhos, mas detalhe tá certo" → scope: platform-cache, tags: rows
  • "Pagamentos errados no checkout" → scope: service-api, tags: payments
  • "Página /alguma-coisa tá com HTML antigo mesmo após /api/cache/purge" → scope: zone

Playbook 5 — Diagnosticar staleness

Quando usar: "tá dando velho mas eu não sei onde", antes de chutar um purge.

Tempo: ~10s.

Passos:

  1. Actions → Cache Status → Run workflow
  2. Inputs:
    • environment: vera-bet-br
    • include_state: true (probe live state)
  3. Run.
  4. Abrir o step summary. Vai mostrar uma tabela com:
    • Qual resource está warm em CF Cache API
    • Quantos segundos de age (desde a última população)
    • Quantos segundos fresh sobram antes de virar stale
    • Quais tags cada resource tem

Interpretação:

  • Primary hit ❌ em vários resources → cache está cold, próxima request vai pagar custo de BFF
  • Age > TTL mas Fresh? ⚠️ → resource está stale, SWR vai revalidar na próxima request
  • Resource esperado não aparece → não está declarado na policy (BYPASS silencioso). Veja Playbook 7.

Playbook 6 — Inspeção direta via curl

Pra automação, scripts, ou quando o GitHub Actions tá fora:

# Variáveis (substituir)
TARGET=vera.bet.br
SECRET=$FRONT_CT_CACHE_PURGE_SECRET
WORKER_KEY=$FRONT_CT_CF_WORKER_KEY

# 1) Inspecionar policy declarada
curl -s "https://$TARGET/api/dev/cache-policy" \
-H "X-Cache-Secret: $SECRET" | jq .

# 2) Inspecionar estado live (com TTLs restantes)
curl -s "https://$TARGET/api/cache/inspect?include=state" \
-H "X-Cache-Secret: $SECRET" | jq .

# 3) Inspecionar só uma tag
curl -s "https://$TARGET/api/cache/inspect?tag=brand&include=state" \
-H "X-Cache-Secret: $SECRET" | jq .

# 4) Purge por tags
curl -s -X POST "https://$TARGET/api/cache/purge" \
-H "X-Cache-Secret: $SECRET" \
-H "cf-worker-key: $WORKER_KEY" \
-H "Content-Type: application/json" \
-d '{"tags": ["brand", "catalog"]}' | jq .

# 5) Purge tudo da brand (incluindo service-api)
curl -s -X POST "https://$TARGET/api/cache/purge" \
-H "X-Cache-Secret: $SECRET" \
-H "cf-worker-key: $WORKER_KEY" \
-H "Content-Type: application/json" \
-d '{}' | jq .

Playbook 7 — Adicionar resource novo ao platform-cache

Quando usar: novo serviço/módulo precisa cachear dados do BFF de forma agregada.

Tempo: ~15min, incluindo PR review.

Passos:

  1. Define o resource no front-ops/config/cache/defaults.yml:

    myNewResource:
    enabled: true
    ttlSeconds: 600 # 10min
    staleWhileRevalidateSeconds: 300
    staleIfErrorSeconds: 86400
    fallbackEnabled: false # ou true se for hot
    storage:
    primary: cache_api
    snapshot: none # ou kv
    keyPrefix: myNewResource
    tags: ["catalog", "my-domain"]
  2. Wire-up no service do brand worker:

    // app/services/my-new.cache.server.ts
    export async function getMyData(deps: Deps) {
    const result = await engine.fetch(
    "myNewResource",
    () => fetchFromBff(deps),
    { waitUntil: deps.ctx?.waitUntil },
    );
    return result.data;
    }
  3. (Opcional) Adicione ao service-api se o BFF path precisar de cache no proxy também:

    Em front-ops/config/cache/service-api-defaults.yml:

    /v2/my/bff/path:
    ttl: 1800
    methods: ["GET"]
    tags: ["catalog", "my-domain"]
  4. PR em front-ops com as duas mudanças.

  5. Deploy explícito do brand worker. Um push no front-ops não redeploya o brand worker automaticamente — o worker lê PLATFORM_CACHE_POLICY_JSON em deploy-time. Pra ativar o novo resource, rode o workflow deploy.yml manualmente (ou aguarde o próximo deploy de código do brand worker).

  6. Valida rodando Cache Status workflow — o novo resource deve aparecer na tabela.

Atenção:

  • Resource user-scoped? Use fetchWithKey(resource, userId, fetcher) e adicione tags: ["user-scoped"] pra documentar. Nunca use fetch() sem suffix em resource per-user.
  • KV ON (fallbackEnabled: true + snapshot: kv) é caro (KV writes custam $). Use só pra resources hot ou pra cross-DC warm-up crítico.

Playbook 8 — Deploy não invalidou cache esperado

Sintoma: após deploy, mudança no código não aparece no site. (Normalmente o deploy.yml dispara post-deploy purge automático.)

Diagnóstico:

  1. Verifica o run do deploy.yml. Procura por:
    • Step "Purge platform cache after deploy" — status 200?
    • Step "Purge SSR cache (CF zone)" — status 200?
    • Step "Warm up cache" — todos 200/304?
  2. Se algum step falhou: re-roda manual-cache-purge.yml com scope: all.

Causas comuns:

  • FRONT_<X>_CACHE_PURGE_SECRET mismatch entre worker e workflow → 401 no step
  • cf_zone errado em deploy.yml → zone purge skip (warning)
  • Token CF sem permissão "Cache Purge:Purge" → 403

Veja config/brands/README.md no front-ops pro checklist completo de tokens CF.


Playbook 9 — Resource em BYPASS silencioso

Sintoma: dev adicionou engine.fetch("foo", ...) mas o resource não está cacheando.

Diagnóstico:

  1. Roda cache-status.yml na env.
  2. Procura foo na tabela.
  3. Se não aparece, é BYPASS — não está na policy.
  4. Logs do worker (wrangler tail) deveriam mostrar uma vez:
    [platform-cache] resource "foo" has no policy entry — running in BYPASS mode

Solução: PR no front-ops/config/cache/defaults.yml (Playbook 7).


Playbook 10 — Forçar invalidação direta no Cloudflare (último recurso)

Quando usar: workflows do GH down, ou cache.purge endpoint do brand worker quebrado.

Tempo: ~2min.

Passos:

  1. Cloudflare Dashboard → Zone (ex: vera.bet.br) → Caching → Configuration
  2. Purge by URL se sabe exatamente o que zerar, ou
  3. Purge Everything se é nuclear.

OU via API:

# Zone ID (lookup)
curl -s -X GET \
"https://api.cloudflare.com/client/v4/zones?name=vera.bet.br&account.id=$ACCOUNT_ID" \
-H "Authorization: Bearer $CF_API_TOKEN" | jq '.result[0].id'

# Purge everything
curl -s -X POST \
"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"purge_everything": true}'

Atenção: isso afeta SÓ o CF zone cache (SSR HTML em edge). Não toca platform-cache nem service-api. Pra purgar app-level use o manual-cache-purge.yml.


Playbook 11 — Reset completo de cache-key prefix (escalada)

Cenário extremo: uma mudança de schema do BFF causou que payloads cacheados em KV/CF Cache estão com formato incompatível com a nova versão do código.

Como funciona:

Cada camada tem um prefix versionado. Bumpar o prefix significa todos os caches dessa camada ficam órfãos instantaneamente.

CamadaOnde bumparVersão atual
platform-cache CF Cache API namespacecore/packages/platform-cache/src/generation.ts (single source of truth)platform-cache-apcsrasj-v3
api-client cache keycore/packages/api-client/src/cache.ts (DEFAULT_CACHE_KEY_PREFIX)api-cache-apcsrasj-v3
service-api proxyfront-service-api/src/index.ts (CACHE_GENERATION env / fallback)apcsrasj-v3

Nota: um bump de CACHE_GENERATION orphana (não deleta) as entries KV antigas. Elas TTL-evict dentro da janela do ceiling (≤1h). Para wipe instantâneo, seria necessário um POST { all: true } adicional ao service-api — isso é follow-up futuro. Veja Invariante 9.

Passos:

  1. PR bumpando o prefix (v1v2, v3v4, etc) no arquivo acima.
  2. Para core packages: tem que publicar versão nova no GH Packages.
  3. Para brand worker: redeploy automático puxa o package novo + invalida tudo no novo namespace.
  4. Para service-api: redeploy via pnpm deploy:ct / :bt.
  5. Aviso pré-deploy ao time: vai ter cold-start massivo. Considere fazer em horário de baixo tráfego.

Quando NÃO fazer: se um purge normal funcionaria. Bump de prefix é última opção.


Sumário rápido — escolha o playbook certo

SituaçãoPlaybook
Backoffice mudou e não reflete1
Jogo novo não aparece2
"Tá tudo errado, zera tudo"3
Debug — quero saber em qual camada está o problema4, 5
Inspeção rápida via curl6
Adicionar resource novo7
Deploy não invalidou esperado8
engine.fetch("foo") não cacheia9
Workflow GH fora, preciso resolver via CF direto10
Mudança de schema do BFF quebrou caches existentes11