Diagnosticar falhas de Workers

CloudflareBeginner
Pratique Agora

Introdução

Uma API de suporte retorna uma exceção pouco útil quando uma dependência está lenta. Você reproduzirá o sintoma, fará a correlação com um ID de requisição e corrigirá o handler para que os chamadores recebam uma falha limitada e significativa, enquanto as requisições saudáveis continuam funcionando. Em seguida, você verificará as respostas reais na nuvem e um fluxo separado de logs ao vivo.

Comece nesta VM nova usando sua própria conta de aprendizagem. Os pré-requisitos são um deployment comum com Wrangler, service bindings e testes locais; nenhum Worker ou VM anterior será reutilizado. A configuração instala Node.js 22.22.0, Wrangler 4.131.1 e Miniflare 4.20260730.0, além de fornecer o chamador com falha e um upstream sintético. O upstream retorna dados sintéticos, um 503 controlado ou um atraso de 2,5 segundos. Não é necessário usar banco de dados, domínio comprado ou realizar um experimento de alta carga.

Uma exceção do runtime, um HTTP 504 deliberado e uma falha por limite de execução são observações diferentes. Você examinará cada tipo de evidência sem tratar toda resposta 5xx como uma falha da plataforma.

Reproduzir e correlacionar o timeout

Nesta etapa, reproduza localmente uma exceção causada por uma dependência lenta. Leia o chamador e o upstream fornecido. O chamador tem um prazo de 400 ms, mas não captura uma rejeição de fetch; o modo lento do upstream espera 2,5 segundos.

cd /home/labex/project/failure-diagnostics
cat src/index.js
cat upstream/index.js

Gere uma base exclusiva para os recursos. O primeiro EOF sem aspas expande essa variável nas duas configurações. O service binding UPSTREAM mantém o fixture privado; um hostname na URL da requisição não seleciona um serviço público.

WORKER_NAME="labex-diagnose-$(node -p "require('node:crypto').randomBytes(6).toString('hex')")"
cat > wrangler.jsonc <<EOF
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-07-30",
  "workers_dev": true,
  "preview_urls": false,
  "services": [{"binding": "UPSTREAM", "service": "$WORKER_NAME-upstream"}]
}
EOF
cat > upstream/wrangler.jsonc <<EOF
{
  "name": "$WORKER_NAME-upstream",
  "main": "index.js",
  "compatibility_date": "2026-07-30",
  "workers_dev": false,
  "preview_urls": false
}
EOF

Execute as duas configurações em um único processo de desenvolvimento local. O job em segundo plano mantém o terminal disponível; > e 2>&1 gravam a saída e os erros em dev.log. Aguarde a mensagem Ready antes de enviar requisições.

npx wrangler dev -c wrangler.jsonc -c upstream/wrangler.jsonc --ip 0.0.0.0 --port 8080 > dev.log 2>&1 &
cat dev.log

Use -H para anexar um pequeno ID de requisição sintético. O handler aceita apenas um formato restrito de ID e gera um ID caso contrário. --max-time limita o cliente curl; ele é separado do prazo definido no handler.

curl -i --max-time 6 -H "X-Request-ID: healthy-one" "http://127.0.0.1:8080/api/check?mode=healthy"
curl -i --max-time 6 -H "X-Request-ID: slow-one" "http://127.0.0.1:8080/api/check?mode=slow"
cat dev.log

A requisição saudável retorna 200 com dados sintéticos do upstream. O modo lento deve retornar um erro local 500 e mostrar o registro request_started de slow-one, seguido por uma exceção de timeout não capturada. A página de erro local exata e o stack podem variar. Isso comprova que o prazo rejeita a operação; não comprova que existe uma resposta de erro útil. Execute a verificação antes de alterar o chamador.

Corrigir a resposta de falha e os diagnósticos

Nesta etapa, capture a falha limitada do upstream e mantenha os diagnósticos úteis sem registrar headers ou credenciais. Pare o job atual usando o número real dele.

jobs
kill %1

Substitua o chamador pelo handler corrigido completo abaixo. O delimitador entre aspas preserva o JavaScript literalmente. Um 504 identifica o prazo da dependência do chamador; um 502 identifica uma resposta do upstream ou um protocolo com falha. As chamadas bem-sucedidas mantêm o resultado do upstream. elapsed_ms é o tempo decorrido no relógio, não o uso de CPU. O log e a resposta compartilham um ID de requisição para que você possa acompanhar uma única requisição em todo o sistema.

cat > src/index.js <<'JS'
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    if (url.pathname === '/health') return Response.json({status: 'ok'});
    if (url.pathname !== '/api/check') return Response.json({error: 'not_found'}, {status: 404});
    if (request.method !== 'GET') return Response.json({error: 'method_not_allowed'}, {status: 405});
    const mode = url.searchParams.get('mode') || 'healthy';
    if (!['healthy', 'slow', 'fail'].includes(mode)) {
      return Response.json({error: 'invalid_mode'}, {status: 400});
    }
    const suppliedId = request.headers.get('X-Request-ID') || '';
    const requestId = /^[a-z0-9-]{1,64}$/.test(suppliedId) ? suppliedId : crypto.randomUUID();
    const headers = {'X-Request-ID': requestId, 'Cache-Control': 'no-store'};
    const started = Date.now();
    console.log(JSON.stringify({event: 'request_started', request_id: requestId, mode}));
    const upstreamUrl = new URL('https://diagnostic.internal/check');
    upstreamUrl.searchParams.set('mode', mode);
    upstreamUrl.searchParams.set('probe', requestId);
    const signal = AbortSignal.timeout(400);
    const failure = (event, status, detail = {}) => {
      console.error(JSON.stringify({event, request_id: requestId, mode, status,
        elapsed_ms: Date.now() - started, ...detail}));
      return Response.json({error: event, requestId}, {status, headers});
    };
    try {
      const response = await env.UPSTREAM.fetch(upstreamUrl, {signal});
      if (!response.ok) return failure('upstream_status', 502, {upstream_status: response.status});
      const data = await response.json();
      if (data.service !== 'labex-diagnostic-fixture' || data.status !== 'ok' || data.probe !== requestId) {
        return failure('upstream_protocol', 502);
      }
      console.log(JSON.stringify({event: 'request_complete', request_id: requestId,
        mode, status: 200, elapsed_ms: Date.now() - started}));
      return Response.json({status: 'ok', requestId, upstream: data}, {headers});
    } catch {
      return signal.aborted ? failure('upstream_timeout', 504) : failure('upstream_exception', 502);
    }
  }
};
JS
npx wrangler dev -c wrangler.jsonc -c upstream/wrangler.jsonc --ip 0.0.0.0 --port 8080 > dev.log 2>&1 &
cat dev.log

Depois de ver Ready, compare os três modos e a rota de integridade que não foi alterada. Cada falha deve terminar rapidamente; esperar mais tempo pelo modo lento não é a correção.

curl -i --max-time 6 -H "X-Request-ID: healthy-two" "http://127.0.0.1:8080/api/check?mode=healthy"
curl -i --max-time 6 -H "X-Request-ID: slow-two" "http://127.0.0.1:8080/api/check?mode=slow"
curl -i --max-time 6 -H "X-Request-ID: fail-two" "http://127.0.0.1:8080/api/check?mode=fail"
curl -i http://127.0.0.1:8080/health
cat dev.log

Espere 200/504/502 para healthy/slow/fail. Cada resposta inclui o ID de requisição no JSON e em X-Request-ID. Os logs associam request_started a request_complete, upstream_timeout ou upstream_status. A última categoria registra o 503 do upstream separadamente do 502 do chamador. Uma falha capturada pode ter um resultado bem-sucedido no runtime porque o handler foi concluído normalmente, mesmo que o status HTTP seja 504 ou 502.

Compare esse resultado com o exemplo fornecido de limite de execução:

cat evidence/execution-limit.json

Esse arquivo é explicitamente uma evidência sintética para ensino, não uma captura do seu Worker. O resultado exceededCpu identifica uma falha por limite de execução; não há garantia de que um catch da aplicação será executado depois que o runtime interromper a execução. Esperar pelo upstream assíncrono deste laboratório não equivale a consumir tempo de CPU. Investigue cálculos ou trabalho de requisição dispendiosos antes de considerar limites; não remova o prazo nem gere carga para imitar este exemplo. A referência oficial de erros explica as categorias de exceções e limites, e a documentação sobre resultados do runtime diferencia o resultado do status HTTP.

Execute a verificação. Ela inicia um runtime isolado com seu próprio fixture e seus próprios IDs de requisição, verifica os contratos de sucesso e falha e confirma que um header Authorization sintético não aparece nos logs capturados da aplicação. Os arquivos de log do aluno não são a prova independente.

Verificar requisições, logs e métricas ao vivo

Nesta etapa, verifique o comportamento corrigido na sua conta de aprendizagem. Pare o desenvolvimento local e autorize esta VM nova usando o mesmo fluxo de dispositivo com escopo ensinado anteriormente.

jobs
kill %1
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_tail:read

Abra o link exibido, informe o código e aprove a conta de aprendizagem correta no navegador. Confirme o nome e o ID reais da conta na saída padrão do Wrangler.

npx wrangler whoami --json

Substitua YOUR_ACCOUNT_ID pelo ID real. Este comando comum do Node salva o ID nas duas configurações do projeto, para que cada deployment deixe explícito quem é o proprietário.

node -e 'const fs=require("node:fs");for(const p of ["wrangler.jsonc","upstream/wrangler.jsonc"]){const c=JSON.parse(fs.readFileSync(p));c.account_id="YOUR_ACCOUNT_ID";fs.writeFileSync(p,JSON.stringify(c,null,2)+"\n");}'
cat wrangler.jsonc upstream/wrangler.jsonc
npx wrangler deploy -c upstream/wrangler.jsonc
npx wrangler deploy

O fixture não tem endpoint público. Copie abaixo a URL workers.dev real do chamador. Se a conta precisar do registro inicial do subdomínio, siga o procedimento de Deploy Your First Cloudflare Worker antes de continuar.

APP_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"

Inicie um fluxo ao vivo legível. Aguarde até events.log informar Connected antes de enviar requisições; a simples existência do arquivo não indica que o fluxo está pronto.

npx wrangler tail --format pretty > events.log 2> tail-errors.log &
cat events.log
curl -i --max-time 6 -H "X-Request-ID: cloud-healthy" "$APP_URL/api/check?mode=healthy"
curl -i --max-time 6 -H "X-Request-ID: cloud-slow" "$APP_URL/api/check?mode=slow"
curl -i --max-time 6 -H "X-Request-ID: cloud-fail" "$APP_URL/api/check?mode=fail"
cat events.log

Encontre as respostas esperadas 200/504/502 e os IDs correspondentes nos logs da aplicação ao vivo. Se um evento ainda não tiver chegado, examine o mesmo log novamente após alguns segundos; não altere a aplicação para fabricá-lo. Pare e examine tail-errors.log se o fluxo tiver terminado. Uma saída legível pode marcar a invocação capturada com 504 como Ok: isso significa que o runtime foi concluído, não que o upstream estava saudável.

No Dashboard, abra o chamador exato na conta selecionada, confirme que o binding UPSTREAM aponta para este fixture e examine Metrics. Os gráficos disponíveis agregam requisições e erros de invocação e podem atrasar em relação a um teste curto; registre o que estiver realmente visível, sem exigir um total diferente de zero imediatamente. Use os logs ao vivo e as respostas HTTP como evidência de requisições individuais. Um 504 capturado pode aparecer nos dados de status das respostas HTTP sem ser contabilizado como uma exceção não capturada do runtime. A referência de métricas explica a agregação e as categorias de invocação.

Em Compute → Workers & Pages, abra o chamador exato e selecione Metrics. Verifique a trilha de navegação do Worker, o filtro de versão implantada e um intervalo de tempo que inclua suas requisições. O botão de atualização fica ao lado do seletor de intervalo de tempo. A captura de tela abaixo foi feita pouco depois das requisições sintéticas saudável, lenta e com falha no upstream; os cartões ainda mostravam No data. Essa é uma observação válida de análises atrasadas, não uma prova de que nenhuma requisição foi executada ou de que a correção falhou. Seu nome, ID da versão e totais serão diferentes. Não gere carga extra apenas para reproduzir uma imagem.

Worker Metrics with version and time-range controls before analytics data has arrived

Execute a verificação enquanto estiver autorizado. Ela consulta a propriedade e o estado dos bindings, envia novas requisições independentes e captura um fluxo ao vivo separado. Aguarde aproximadamente um minuto. Um fluxo indisponível ou incompleto é inconclusivo; verifique se a conexão está pronta e tente novamente. Nunca trate logs ausentes como sucesso. Depois que a verificação for aprovada, pare o tail do aluno usando o número atual do job.

jobs
kill %1

Excluir os Workers de diagnóstico

Nesta etapa, remova apenas o chamador e o fixture deste laboratório enquanto ainda estiver autorizado. Revise os dois nomes e a conta correspondente antes de excluir primeiro o chamador.

cat wrangler.jsonc upstream/wrangler.jsonc
npx wrangler delete
npx wrangler delete -c upstream/wrangler.jsonc

Em cada prompt que corresponder a um dos nomes, pressione a única tecla y. A CLI fixada pode exibir um diagnóstico de autenticação relacionado à limpeza de KV legado depois de excluir um Worker; não amplie as permissões por causa disso nem presuma que erros arbitrários comprovam a exclusão. Atualize o Dashboard e execute a verificação. Os dois nomes devem estar ausentes de um inventário autenticado bem-sucedido. Preserve a conta, o subdomínio e os recursos não relacionados.

Desconectar a VM

Nesta etapa, desconecte a VM depois de verificar a exclusão dos recursos. Fechar o terminal ou sair da conta não removeria os recursos da nuvem.

npx wrangler logout
npx wrangler whoami --json

Espere loggedIn=false; o comando pode terminar com código diferente de zero nesse estado não autenticado. Execute a verificação final. O login do navegador e a conta de aprendizagem poderão ser reutilizados em um laboratório novo posteriormente.

Resumo

Você reproduziu um timeout não tratado, corrigiu falhas limitadas de dependências e correlacionou IDs de requisição entre respostas e logs estruturados. O comportamento saudável foi preservado. Você distinguiu falhas HTTP da aplicação de resultados do runtime e de evidências sintéticas de limite de CPU, verificou o comportamento real na nuvem, removeu os dois Workers e desconectou a VM.