Lidar com atualizações de configuração atrasadas

CloudflareBeginner
Pratique Agora

Introdução

Um centro de ajuda pode ler o tema e o banner de boas-vindas no KV, permitindo que um editor altere essas configurações sem implantar um novo código. Após uma atualização, leitores em locais diferentes podem ver versões diferentes por algum tempo. Durante essa transição, a aplicação deve continuar utilizável, sem presumir que toda leitura retornará as configurações mais recentes.

Você criará um leitor de configuração versionado com padrões seguros, testará uma sequência simulada deliberadamente com valores antigos e novos e, em seguida, fará uma atualização real na nuvem. Uma versão é um rótulo armazenado junto com as configurações; ela ajuda a identificar o valor recebido. Ela não transforma o KV em um banco de dados fortemente consistente nem garante que solicitações consecutivas vejam números de versão crescentes.

Conclua primeiro os laboratórios anteriores sobre KV. Esta VM independente tem Node.js 22.22.0 e o Wrangler 4.131.1 instalado localmente no projeto em /home/labex/project/delayed-config. Use sua própria conta de aprendizado com as mesmas permissões de leitura da conta, gravação no Worker e gravação no KV. O exercício cria um Worker e um namespace descartáveis e expõe apenas configurações sintéticas de exibição. Não é necessário fazer upgrade pago nem comprar um domínio para esse pequeno conjunto de dados. Essas configurações não controlam autorização, pagamentos ou outras decisões que exigem uma atualização autoritativa imediata.

Conectar um armazenamento de configuração independente

Nesta etapa, você conectará um namespace novo para armazenar a configuração de exibição. O binding CONFIG mantém a referência ao recurso na configuração padrão do Wrangler. Use recursos novos do laboratório para que configurações deliberadamente inválidas não afetem outra aplicação.

Entre no projeto preparado:

cd /home/labex/project/delayed-config

Gere um nome exclusivo uma única vez. openssl rand -hex 6 imprime um sufixo aleatório; $(...) insere esse sufixo no nome. A variável do shell mantém esse nome disponível para os próximos comandos executados neste terminal.

WORKER_NAME="labex-config-$(openssl rand -hex 6)"
printf '%s\n' "$WORKER_NAME"

Autorize esta VM. Além de ler a identidade da sua conta, Workers Scripts Write permite implantar e excluir recursos, e Workers KV Write permite gerenciar o namespace e as chaves deste laboratório.

npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_kv:write

Abra no navegador o link do dispositivo exibido, informe o código atual, revise as permissões solicitadas e a conta de aprendizado e autorize o Wrangler. O acesso em segundo plano também pode aparecer na página de consentimento. Volte ao terminal e aguarde a conclusão do login.

Revise as mesmas permissões de gravação no Worker e no KV apresentadas anteriormente neste curso e confirme a conta de aprendizado.

npx wrangler whoami --json

Confirme loggedIn: true e o name da conta de aprendizado, mesmo que apenas uma conta esteja listada. Copie o id dessa conta. Salve-o na configuração abaixo, substituindo YOUR_ACCOUNT_ID antes de executar o comando. O here-document do cat grava em um arquivo tudo o que estiver entre as duas linhas JSON; > substitui o arquivo. Como o delimitador não está entre aspas, o shell poderá inserir $WORKER_NAME.

cat > wrangler.jsonc <<JSON
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-07-30",
  "account_id": "YOUR_ACCOUNT_ID",
  "workers_dev": true
}
JSON

Crie um namespace nessa conta. O título dele compartilha o nome exclusivo do Worker para que você possa reconhecer os dois recursos depois. --update-config=false deixa a edição do binding visível para você, em vez de alterar o arquivo automaticamente.

npx wrangler kv namespace create "$WORKER_NAME-config" --update-config=false

A saída inclui o ID do novo namespace. Copie-o e substitua YOUR_ACCOUNT_ID e YOUR_NAMESPACE_ID nesta configuração completa. O nome do binding CONFIG é escolhido pelo seu código; o ID identifica o recurso real na Cloudflare.

cat > wrangler.jsonc <<JSON
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-07-30",
  "account_id": "YOUR_ACCOUNT_ID",
  "workers_dev": true,
  "kv_namespaces": [
    { "binding": "CONFIG", "id": "YOUR_NAMESPACE_ID" }
  ]
}
JSON
npx wrangler kv namespace list

Localize o título do namespace deste laboratório e compare o ID dele com o ID no arquivo. Outros namespaces podem estar presentes; não os altere. Essa configuração registra qual conta e qual recurso os próximos comandos deverão usar. Um binding é uma referência a um namespace, não uma cópia dos dados dele.

Ler configurações versionadas com padrões seguros

Nesta etapa, você permitirá que as duas versões válidas produzam respostas utilizáveis. Configurações de exibição ausentes ou danificadas usarão como fallback um tema claro simples e nenhum banner. Assim, uma configuração opcional de apresentação não interromperá o centro de ajuda.

Grave o handler. O objeto fixo defaults não contém estado específico da solicitação e nunca é modificado. Cada solicitação lê seu próprio resultado do KV.

cat > src/index.js <<'JS'
const defaults = { version: 0, theme: "light", banner: "", source: "default" };

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    if (url.pathname === "/health") return Response.json({ status: "ok" });
    const key = url.searchParams.get("key") ?? "config:current";
    if (url.pathname !== "/settings" || !/^config:[a-z0-9-]{1,20}$/.test(key)) {
      return new Response("Not found", { status: 404 });
    }
    let value;
    try {
      value = await env.CONFIG.get(key, { type: "text", cacheTtl: 60 });
    } catch {
      return Response.json({ error: "Settings temporarily unavailable" }, { status: 503 });
    }
    if (value === null) return Response.json(defaults);
    let settings;
    try {
      settings = JSON.parse(value);
    } catch {
      return Response.json(defaults);
    }
    if (!settings || !Number.isSafeInteger(settings.version) || settings.version < 1 ||
        !["light", "dark"].includes(settings.theme) ||
        typeof settings.banner !== "string" || settings.banner.length > 80) {
      return Response.json(defaults);
    }
    return Response.json({
      version: settings.version, theme: settings.theme,
      banner: settings.banner, source: "stored"
    });
  }
};
JS

A solicitação ao KV usa cacheTtl: 60, uma duração do cache de leitura em segundos. Isso não expira a chave armazenada. Também não instrui cada local a buscar à força o valor mais recente. Tanto os valores existentes quanto os resultados de chaves ausentes podem ser armazenados em cache. Faça gravações com pouca frequência e projete a aplicação para tolerar uma configuração válida mais antiga.

O handler valida a versão, o tema compatível e o tamanho do banner antes de usá-los. A rota /health responde sem ler configurações opcionais. Uma falha de armazenamento ainda produz explicitamente 503 em /settings; a aplicação não informa falsamente que carregou os padrões com sucesso a partir do armazenamento.

Crie dois arquivos pequenos de versão. Manter cada valor pretendido em um arquivo comum facilita a inspeção antes da gravação:

cat > config-v1.json <<'JSON'
{"version":1,"theme":"light","banner":"Welcome"}
JSON
cat > config-v2.json <<'JSON'
{"version":2,"theme":"dark","banner":"New help center"}
JSON

Grave-os em chaves de fixture locais separadas, além de um valor malformado. Essas chaves tornam as entradas possíveis reproduzíveis; elas não simulam o tempo de propagação da rede da Cloudflare.

npx wrangler kv key put config:v1 --path config-v1.json --binding CONFIG --local
npx wrangler kv key put config:v2 --path config-v2.json --binding CONFIG --local
npx wrangler kv key put config:broken broken-json --binding CONFIG --local
npx wrangler dev --local --ip 0.0.0.0 --port 8080 > local.log 2>&1 &
DEV_PID=$!
cat local.log

Aguarde a mensagem de que o servidor está pronto. Em seguida, compare as duas chaves selecionadas explicitamente:

curl -i 'http://127.0.0.1:8080/settings?key=config:v1'
curl -i 'http://127.0.0.1:8080/settings?key=config:v2'

Ambas retornam HTTP 200 com source: "stored". A versão 1 usa o tema claro e Welcome; a versão 2 usa o tema escuro e New help center. Nenhuma das versões depende do resultado de uma solicitação anterior.

curl -i 'http://127.0.0.1:8080/settings?key=config:missing'
curl -i 'http://127.0.0.1:8080/settings?key=config:broken'

Ambas devem retornar {"version":0,"theme":"light","banner":"","source":"default"}. A versão 0 é o rótulo padrão da aplicação; ela não é uma revisão armazenada no KV.

curl -i http://127.0.0.1:8080/health

Espere {"status":"ok"}. Mantenha o servidor local em execução até a limpeza.

Exercitar uma sequência controlada de leituras antigas

Nesta etapa, você testará o handler com uma sequência previsível: antigo, novo, antigo novamente, novo, ausente e inválido. Esta é uma fixture de teste, uma entrada fornecida deliberadamente para tornar repetível uma situação que, de outra forma, seria imprevisível. Ela não comprova que uma solicitação real da Cloudflare estava obsoleta.

Crie um teste pequeno em Node.js usando a biblioteca padrão de asserções. Ele importa o handler que você escreveu e fornece a mesma interface CONFIG.get() com valores de retorno controlados:

cat > test-config.mjs <<'JS'
import assert from "node:assert/strict";
import worker from "./src/index.js";

const older = JSON.stringify({ version: 1, theme: "light", banner: "Welcome" });
const newer = JSON.stringify({ version: 2, theme: "dark", banner: "New help center" });
// A controlled fixture: these values simulate different reads, not a cloud outage.
const values = [older, newer, older, newer, null, "broken-json"];
const expectedVersions = [1, 2, 1, 2, 0, 0];
for (let i = 0; i < values.length; i += 1) {
  const env = { CONFIG: { get: async () => values[i] } };
  const response = await worker.fetch(new Request("https://example.test/settings"), env);
  assert.equal(response.status, 200);
  const body = await response.json();
  assert.equal(body.version, expectedVersions[i]);
  assert.ok(["light", "dark"].includes(body.theme));
  assert.equal(typeof body.banner, "string");
}
console.log("Controlled old/new/missing/invalid reads stayed usable.");
JS
node test-config.mjs

Espere Controlled old/new/missing/invalid reads stayed usable. Uma asserção malsucedida interrompe o comando com um erro. O valor antigo repetido é intencional: não adicione uma variável global do processo chamada “versão mais recente” para ocultá-lo. Os Workers podem ser executados em instâncias diferentes, portanto uma variável desse tipo não pode estabelecer uma versão mais recente para toda a conta.

Uma atualização de configuração deve manter utilizáveis os leitores de valores válidos mais antigos durante a transição. Essa abordagem é adequada para um banner ou tema. Ela não tornaria o KV apropriado para revogar imediatamente o acesso de alguém. O teste real na nuvem vem a seguir; ele pode mostrar o novo valor já na primeira solicitação, e esse é um resultado válido.

Implantar e estabelecer a primeira versão na nuvem

Nesta etapa, você estabelecerá uma base remota real antes de alterá-la. Somente a configuração atual e a fixture de fallback malformada devem pertencer ao namespace na nuvem deste laboratório.

npx wrangler kv key put config:current --path config-v1.json --binding CONFIG --remote
npx wrangler kv key put config:broken broken-json --binding CONFIG --remote
npx wrangler deploy

Confirme o nome exclusivo do Worker e o binding CONFIG e copie a URL pública real:

WORKER_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$WORKER_URL/settings"

Espere a versão 1, o tema light, o banner Welcome e source: "stored". Se necessário, aguarde a disponibilidade do hostname e a visibilidade do KV; um erro de rede não é uma resposta de configuração. Execute a verificação independente desta etapa antes de substituir a versão 1. Ela confirma a conta selecionada, o valor armazenado, o binding implantado, os padrões e a resposta de integridade.

Observar uma atualização real sem exigir uma leitura antiga

Nesta etapa, você atualizará a configuração armazenada sem alterar o código do Worker. Inspecione o novo valor pretendido e grave-o na mesma chave remota:

cat config-v2.json
npx wrangler kv key put config:current --path config-v2.json --binding CONFIG --remote
npx wrangler kv key get config:current --binding CONFIG --remote --text

A leitura de gerenciamento deve conter a versão 2. Agora inspecione o que a aplicação vê:

curl -i "$WORKER_URL/settings"

Você pode ver a versão 2 imediatamente ou uma versão anterior válida enquanto as leituras convergem. Não exija uma resposta obsoleta para “provar” a consistência eventual nem regrave rapidamente a chave para provocar uma. Se necessário, repita a solicitação HTTP em intervalos de 15 segundos por até cinco minutos. Essa é uma janela de observação limitada para o exercício, não uma promessa de que todos os locais globais convergirão em cinco minutos.

Continue quando o endpoint retornar {"version":2,"theme":"dark","banner":"New help center","source":"stored"}. Se a convergência não ocorrer dentro dessa janela de observação, verifique a conta e o binding e informe um resultado inconclusivo. A verificação independente exige que a versão realmente armazenada e a resposta real coincidam; um arquivo local ou uma fixture de teste não atende a esse requisito.

curl -i "$WORKER_URL/settings?key=config:broken"
curl -i "$WORKER_URL/health"

A configuração de exibição danificada ainda terá um padrão controlado, e a integridade continuará ok. No Dashboard, selecione a mesma conta e inspecione o namespace deste laboratório em Storage & databases → Workers KV. Compare config:current com a versão 2 no seu arquivo. Essa visualização somente leitura mostra o valor gerenciado; ela não pode provar o que todos os locais remotos têm atualmente armazenado em cache.

O teste controlado cobriu a tolerância a valores antigos, enquanto esta atualização real cobriu a implantação e a convergência observada no endpoint de teste. Mantenha essas conclusões separadas. Consulte como o KV funciona para conhecer o modelo de consistência.

Selecione KV Pairs e depois View ao lado de config:current. Use Refresh se a lista ainda não refletir a atualização. O exemplo mostra a versão 2, o tema dark e o banner New help center; o nome gerado do seu namespace será diferente. Não altere o valor nesta verificação.

Configuração da versão 2 no Dashboard

Excluir os recursos descartáveis da nuvem

Nesta etapa, você removerá os dois recursos enquanto o Wrangler ainda estiver autorizado. Um namespace pode continuar existindo depois que o Worker for excluído, portanto excluir apenas a aplicação não remove os dados.

Pare o processo de desenvolvimento local iniciado neste terminal:

kill "$DEV_PID"

Inspecione as referências de recursos salvas antes de excluir qualquer coisa:

cat wrangler.jsonc

Confirme o nome do Worker labex-config-... e o ID do namespace CONFIG. Exclua o Worker selecionado por essa configuração:

npx wrangler delete

Se for solicitado, confirme que o nome exibido corresponde a este laboratório e confirme com y. Em seguida, exclua somente o namespace referenciado por CONFIG:

npx wrangler kv namespace delete --binding CONFIG

Revise o namespace em qualquer solicitação de confirmação antes de aceitar. Mantenha wrangler.jsonc intacto para que a verificação independente possa identificar os recursos que deveriam estar ausentes.

npx wrangler kv namespace list

O namespace deste laboratório deve estar ausente; namespaces não relacionados devem permanecer. Atualize as listas do Dashboard para confirmar que o Worker e o namespace do laboratório desapareceram. Uma solicitação malsucedida ou um login expirado não comprova a exclusão. Execute a verificação desta etapa antes de sair da conta, para que ela possa inspecionar um inventário autorizado.

Encerrar a autorização da VM

Nesta etapa, você desconectará o Wrangler depois que a verificação de limpeza for aprovada. Sair da conta encerra a autorização do Wrangler salva nesta VM; isso não exclui recursos da nuvem nem encerra a sessão comum do Dashboard no navegador.

npx wrangler logout
npx wrangler whoami --json

Confirme que o resultado estruturado informa "loggedIn": false. Esse comando não autenticado pode terminar com um status de saída diferente de zero, o que é esperado aqui. Se houver apenas um erro de conexão, sem um estado de autenticação explícito, tente novamente quando a conexão estiver funcionando.

Os arquivos locais restantes e o estado local do KV pertencem a esta VM descartável. Eles são separados dos recursos da nuvem que você já excluiu. Agora você pode concluir o laboratório.

Resumo

Você criou um leitor de configuração que aceita configurações válidas antigas e novas, usa padrões seguros para valores ausentes ou inválidos e mantém o endpoint de integridade independente dos dados opcionais do KV. Você exercitou uma sequência controlada de leituras antigas, alterou uma chave remota real e observou a convergência da resposta implantada.

Você aprendeu que os rótulos de versão descrevem os dados retornados, enquanto a duração do cache de leitura, a expiração e a consistência forte são questões diferentes. Por fim, você excluiu os recursos descartáveis e saiu da conta. O desafio do curso combinará o binding correto do namespace com o tratamento seguro de avisos.