Introdução
Um banner de manutenção deve desaparecer quando o período do aviso terminar. Se ele continuar visível, os visitantes podem pensar que uma interrupção antiga ainda está acontecendo. Você criará um Worker que lê um aviso do KV e decide se ele ainda deve ser exibido.
Existem dois prazos separados. Um prazo da aplicação informa ao seu código quando parar de exibir a mensagem. Uma expiração do KV informa ao serviço de armazenamento quando remover a entrada. Você manterá deliberadamente um registro antigo no armazenamento para provar que a aplicação consegue ocultar conteúdo expirado mesmo enquanto os dados ainda existem. Depois, você observará um segundo registro expirar automaticamente no KV da nuvem.
Conclua primeiro Serve Account Preferences. Esta VM independente já tem Node.js 22.22.0 e o Wrangler 4.131.1 instalado localmente no projeto em /home/labex/project/temporary-notices. Use sua própria conta de aprendizagem e as mesmas permissões account-read, Worker-write e KV-write. Você criará um Worker e um namespace descartáveis, usará somente mensagens sintéticas e fará a limpeza antes de sair. O exercício curto não exige um domínio comprado nem uma atualização paga. Reserve cerca de cinco minutos para a observação temporizada, além do tempo para escrever e testar o handler.
Conectar um namespace de avisos
Nesta etapa, você conectará um namespace novo para avisos temporários. Use um namespace separado e um nome de Worker exclusivo para que os testes de expiração não removam dados de outra aplicação. O binding NOTICES conectará seu handler a esse recurso.
Entre no projeto preparado:
cd /home/labex/project/temporary-notices
Gere um nome exclusivo uma vez. openssl rand -hex 6 imprime um sufixo aleatório; $(...) o insere no nome. A variável do shell manterá esse nome disponível para os próximos comandos neste terminal.
WORKER_NAME="labex-notices-$(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 fazer deploy e excluir recursos, enquanto 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 de dispositivo exibido, informe o código atual, revise as permissões solicitadas e a conta de aprendizagem 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 escrita para Worker e KV apresentadas em Create a Feature Flag Store. Confirme sua conta de aprendizagem antes de autorizar.
npx wrangler whoami --json
Confirme loggedIn: true e o name da conta de aprendizagem, 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 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 o par mais tarde. --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-notices" --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 NOTICES foi escolhido para o seu código; o ID identifica o recurso real da 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": "NOTICES", "id": "YOUR_NAMESPACE_ID" }
]
}
JSON
npx wrangler kv namespace list
Encontre 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.
Ocultar um aviso antigo antes de excluir os dados
Nesta etapa, você separará o comportamento de exibição da limpeza do armazenamento. Um timestamp é um número que representa um ponto no tempo. Aqui, displayUntil usa segundos Unix, contados a partir do início de 1970 em UTC. Date.now() retorna milissegundos, portanto o handler divide o valor por 1000 antes de compará-los. Usar a mesma unidade evita um erro comum em prazos.
Escreva o handler com este here-document entre aspas:
cat > src/index.js <<'JS'
export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.searchParams.get("key") ?? "notice:maintenance";
if (url.pathname !== "/notice" || !/^notice:[a-z]{1,20}$/.test(key)) {
return new Response("Not found", { status: 404 });
}
let entry;
try {
entry = await env.NOTICES.getWithMetadata(key, "text");
} catch {
return Response.json({ error: "Notice storage unavailable" }, { status: 503 });
}
if (entry.value === null) {
return Response.json({ visible: false, reason: "missing" });
}
let notice;
try {
notice = JSON.parse(entry.value);
} catch {
return Response.json({ visible: false, reason: "invalid" });
}
if (!notice || typeof notice.message !== "string" || !notice.message.trim() ||
!Number.isSafeInteger(notice.displayUntil) || notice.displayUntil <= 0) {
return Response.json({ visible: false, reason: "invalid" });
}
if (Math.floor(Date.now() / 1000) >= notice.displayUntil) {
return Response.json({ visible: false, reason: "expired" });
}
return Response.json({
visible: true, message: notice.message,
kind: entry.metadata?.kind === "maintenance" ? "maintenance" : "general"
});
}
};
JS
O parâmetro de consulta key seleciona um aviso sintético; sem esse parâmetro, o handler usa notice:maintenance. A aplicação oculta avisos ausentes, malformados e expirados com uma resposta JSON explicativa. Uma falha de leitura do KV retorna 503, em vez de fingir que o aviso está ausente. O campo de metadados kind classifica o aviso; metadados ausentes ou inesperados usam general como padrão.
A comparação do prazo usa >=: o aviso fica oculto no momento do prazo, não um segundo depois. Essa verificação é executada a cada solicitação. Uma página da Web que já tenha exibido um banner também precisaria ser atualizada ou removê-lo com seu próprio temporizador; uma resposta do Worker não pode alterar sozinha uma página que já foi renderizada.
Salve localmente um aviso de referência deliberadamente antigo. O prazo 1 representa um instante conhecido de 1970, portanto esse registro já expirou do ponto de vista da aplicação. Omitiremos deliberadamente uma expiração do KV para que o registro continue disponível para inspeção.
npx wrangler kv key put notice:reference '{"message":"Old maintenance notice","displayUntil":1}' --binding NOTICES --local --metadata '{"kind":"maintenance"}'
npx wrangler dev --local --ip 0.0.0.0 --port 8080 > local.log 2>&1 &
DEV_PID=$!
cat local.log
O servidor em segundo plano grava a saída em local.log. Repita o comando de log até que ele indique que está pronto na porta 8080. Agora solicite a referência antiga:
curl -i 'http://127.0.0.1:8080/notice?key=notice:reference'
Espere HTTP 200 e {"visible":false,"reason":"expired"}. As aspas impedem que o ponto de interrogação na URL seja tratado pela sintaxe do shell para nomes de arquivos. Comprove que a entrada ainda existe:
npx wrangler kv key get notice:reference --binding NOTICES --local --text
O JSON ainda estará presente. Seu código, e não uma exclusão automática, impediu que o aviso antigo fosse exibido. Uma chave ausente também deve ser tratada com segurança:
curl -i 'http://127.0.0.1:8080/notice?key=notice:missing'
Espere {"visible":false,"reason":"missing"}. Deixe o servidor local em execução até a limpeza.
Publicar um aviso com dois prazos
Nesta etapa, você fará o deploy do Worker primeiro e, depois, iniciará uma janela curta para o aviso na nuvem. Preparar o endpoint antes de iniciar a contagem dá tempo para inspecionar o resultado ativo.
Crie a mesma referência sem expiração no namespace remoto:
npx wrangler kv key put notice:reference '{"message":"Old maintenance notice","displayUntil":1}' --binding NOTICES --remote --metadata '{"kind":"maintenance"}'
npx wrangler deploy
Confirme o nome gerado do Worker e o binding NOTICES, depois salve a URL pública real exibida na saída:
WORKER_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$WORKER_URL/notice?key=notice:reference"
Espere que a referência antiga seja ocultada como expired. Se o hostname ainda não estiver pronto, aguarde e tente novamente antes de iniciar a parte temporizada. Ainda não solicite a chave de manutenção padrão: leituras de chaves KV ausentes também podem ser armazenadas em cache.
Leia as instruções restantes antes de executar os próximos comandos. date +%s retorna o horário Unix atual da VM; $((...)) executa operações aritméticas no shell. Deixaremos de exibir o aviso depois de três minutos e, um minuto mais tarde, pediremos ao KV que o remova.
DISPLAY_UNTIL=$(($(date +%s) + 180))
KV_EXPIRES=$((DISPLAY_UNTIL + 60))
Grave o payload real da aplicação. O delimitador JSON sem aspas insere no arquivo o prazo numérico:
cat > notice.json <<JSON
{"message":"Maintenance starts soon","displayUntil":$DISPLAY_UNTIL}
JSON
--path lê o valor desse arquivo. --expiration define uma expiração absoluta do KV em segundos Unix; --metadata adiciona a categoria do aviso junto ao valor.
npx wrangler kv key put notice:maintenance --path notice.json --binding NOTICES --remote --expiration "$KV_EXPIRES" --metadata '{"kind":"maintenance"}'
O KV também aceita um TTL relativo (tempo de vida), expresso em segundos a partir da gravação. O Wrangler chama essa opção de --ttl; a API do binding chama-a de expirationTtl. Tanto a expiração relativa quanto a absoluta devem ocorrer pelo menos 60 segundos no futuro. Aqui usamos uma expiração absoluta para que você possa comparar diretamente os dois prazos. Consulte Opções de expiração do KV.
npx wrangler kv key list --binding NOTICES --remote
Encontre notice:maintenance, seu campo expiration e os metadados kind. A referência não tem expiração do KV. Agora leia a mensagem ativa:
curl -i "$WORKER_URL/notice"
Espere HTTP 200 e {"visible":true,"message":"Maintenance starts soon","kind":"maintenance"}. Execute agora a verificação desta etapa, antes que a janela de exibição termine. Ela verifica o valor real na nuvem, os metadados, a expiração do KV, o binding e a resposta ativa. Um timestamp salvo sozinho não prova que o aviso foi armazenado.
Se você perder a janela, repita as duas atribuições de tempo, reescreva notice.json e repita o put remoto com prazos novos. Não repita as gravações rapidamente. Uma leitura armazenada em cache anteriormente pode levar algum tempo para refletir a substituição; aguarde e repita a verificação ativa. Continue somente depois que ela passar.
Após a verificação ativa passar, abra Storage & databases → Workers KV no Dashboard da mesma conta de aprendizagem e selecione o namespace deste laboratório. Abra KV Pairs e clique em View ao lado de notice:maintenance para examinar a mensagem e displayUntil. Confira a expiração do KV e os metadados na lista de chaves da CLI; esta tela mostra o valor armazenado. Faça apenas leituras: o tempo continua passando. Se a chave já expirou, siga para a próxima etapa sem recriá-la apenas para visualizar. O nome e o timestamp da captura são exemplos, não valores para copiar.

Observar conteúdo oculto e expiração automática
Nesta etapa, você observará os dois prazos sem excluir manualmente a chave de manutenção. Não altere notice.json, para poder comparar o payload original com o resultado.
Imprima os dois horários planejados e o horário atual:
printf 'displayUntil=%s
KV expiration=%s
now=%s
' "$DISPLAY_UNTIL" "$KV_EXPIRES" "$(date +%s)"
Aguarde até que o horário atual alcance displayUntil. Estes comandos calculam apenas o atraso restante. Se o prazo já tiver passado, a condição não executará o sleep. sleep recebe segundos; if impede que um atraso negativo seja passado a ele.
WAIT_SECONDS=$((DISPLAY_UNTIL - $(date +%s) + 1))
if [ "$WAIT_SECONDS" -gt 0 ]; then sleep "$WAIT_SECONDS"; fi
curl -i "$WORKER_URL/notice"
A mensagem não deve mais estar visível. Antes da expiração do KV, espere {"visible":false,"reason":"expired"}. Se você voltar depois que o KV já tiver expirado a chave, reason poderá ser missing; ambos os resultados impedem a exibição. A referência mantida continua sendo uma verificação direta do comportamento do prazo da aplicação:
curl -i "$WORKER_URL/notice?key=notice:reference"
npx wrangler kv key get notice:reference --binding NOTICES --remote --text
O endpoint oculta a referência como expired, enquanto a leitura do KV ainda retorna o JSON antigo. Isso demonstra por que o prazo da aplicação é útil mesmo quando os dados armazenados continuam disponíveis.
Agora aguarde o horário de expiração do KV:
WAIT_SECONDS=$((KV_EXPIRES - $(date +%s) + 1))
if [ "$WAIT_SECONDS" -gt 0 ]; then sleep "$WAIT_SECONDS"; fi
npx wrangler kv key list --binding NOTICES --remote
curl -i "$WORKER_URL/notice"
A lista deve manter somente notice:reference; o endpoint padrão deve retornar {"visible":false,"reason":"missing"}. Não execute um comando de exclusão para a chave de manutenção: esta observação trata da expiração automática. Se a entrada continuar visível, repita as verificações somente para leitura em intervalos de 15 segundos por até dois minutos. Essa é uma janela de observação do exercício, não uma garantia sobre o momento exato da exclusão. Se o estado não convergir, informe o resultado inconclusivo em vez de declarar sucesso. Um erro de autorização ou de rede não comprova ausência.
A expiração do KV e o cache de leitura são conceitos diferentes. A expiração se aplica mesmo quando foi solicitada uma duração maior para o cache de leitura. No entanto, alterações na configuração armazenada podem se propagar com atraso, portanto um novo prazo gravado após uma leitura anterior não é uma garantia imediata de agendamento global. Este laboratório verifica o prazo contido no registro que o handler realmente leu.
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 do Worker, portanto excluir somente a aplicação não limpa os dados dela.
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-notices-... e o ID do namespace NOTICES. Exclua o Worker selecionado por esta configuração:
npx wrangler delete
Se for solicitado, verifique se o nome exibido corresponde a este laboratório e confirme com y. Em seguida, exclua somente o namespace referenciado por NOTICES. Isso também removerá o registro de referência mantido:
npx wrangler kv namespace delete --binding NOTICES
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 devem 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 com falha 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 explícito de autenticação, tente novamente quando a conexão funcionar.
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 avisos que verifica um prazo de exibição a cada solicitação, trata dados ausentes e inválidos com segurança e lê uma categoria nos metadados do KV. Um registro antigo mantido provou que ocultar conteúdo não exige excluí-lo primeiro. Um segundo registro demonstrou a expiração do KV com um timestamp absoluto e uma verificação separada da remoção automática.
Você diferenciou um prazo de exibição, uma expiração de armazenamento e o comportamento do cache de leitura; depois, excluiu os recursos descartáveis e encerrou a sessão. Em seguida, você importará e manterá um pequeno catálogo de redirecionamentos no KV.



