Диагностика сбоев Worker

CloudflareBeginner
Практиковаться сейчас

Введение

API поддержки возвращает малоинформативное исключение, когда зависимость отвечает слишком медленно. Вы воспроизведёте этот симптом, сопоставите его с идентификатором запроса и исправите обработчик так, чтобы вызывающая сторона получала ограниченную по времени и понятную ошибку, а успешные запросы по-прежнему выполнялись. Затем вы проверите реальные ответы из облака и отдельный поток журналов в реальном времени.

Начните работу в этой новой виртуальной машине, используя собственную учебную учётную запись. Необходимы базовые навыки развёртывания с помощью Wrangler, работы с привязками сервисов и локального тестирования; ранее созданные Worker или виртуальная машина не используются. В процессе настройки устанавливаются Node.js 22.22.0, Wrangler 4.131.1 и Miniflare 4.20260730.0, а также предоставляются неисправный вызывающий компонент и синтетическая вышестоящая служба. Вышестоящая служба возвращает синтетические данные, управляемый ответ 503 или задерживает ответ на 2,5 секунды. База данных, купленный домен и эксперимент с высокой нагрузкой не нужны.

Исключение времени выполнения, намеренный HTTP-ответ 504 и сбой из-за ограничения выполнения — это разные наблюдения. Вы изучите каждый вид свидетельств и не будете считать любой ответ 5xx сбоем платформы.

Воспроизведение тайм-аута и сопоставление данных

На этом шаге локально воспроизведите исключение из-за медленной зависимости. Изучите вызывающий компонент и предоставленную вышестоящую службу. У вызывающего компонента установлен предел ожидания 400 мс, но нет обработчика для отклонённого fetch; медленный режим вышестоящей службы ожидает 2,5 секунды.

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

Создайте уникальное имя ресурса. Первый EOF без кавычек подставит значение этой переменной в обе конфигурации. Привязка сервиса UPSTREAM оставляет тестовую службу закрытой; имя хоста в URL запроса не выбирает общедоступную службу.

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

Запустите обе конфигурации в одном локальном процессе разработки. Фоновая задача оставит терминал доступным; операторы > и 2>&1 записывают обычный вывод и ошибки в dev.log. Перед отправкой запросов дождитесь сообщения Ready.

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

Используйте -H, чтобы добавить небольшой синтетический идентификатор запроса. Обработчик принимает только идентификатор заданного формата, а во всех остальных случаях создаёт новый. Параметр --max-time ограничивает время ожидания клиента curl; это отдельное ограничение, не связанное с пределом времени в обработчике.

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

Успешный запрос возвращает ответ 200 с синтетическими данными вышестоящей службы. В медленном режиме должен вернуться локальный ответ 500, а в журнале должна появиться запись request_started для slow-one, за которой следует необработанное исключение из-за тайм-аута. Точная страница локальной ошибки и трассировка стека могут отличаться. Это подтверждает, что ограничение времени отклоняет запрос, но не доказывает наличие полезного ответа об ошибке. Перед изменением вызывающего компонента запустите проверку.

Исправление ответа об ошибке и диагностики

На этом шаге обработайте ограниченный по времени сбой вышестоящей службы и сохраните полезность диагностики, не записывая в журнал заголовки или учётные данные. Остановите текущую задачу, используя её фактический номер.

jobs
kill %1

Замените вызывающий компонент полностью исправленным обработчиком ниже. Кавычки вокруг разделителя сохраняют код JavaScript без изменений. Ответ 504 обозначает превышение предела ожидания зависимости вызывающей стороны; ответ 502 обозначает ошибку ответа вышестоящей службы или протокола. При успешном запросе результат вышестоящей службы сохраняется. elapsed_ms — это время, прошедшее по часам, а не загрузка процессора. Журнал и ответ содержат один и тот же идентификатор запроса, поэтому вы можете проследить один запрос через всю систему.

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

После сообщения Ready сравните все три режима и не затронутый маршрут проверки состояния. Каждый сбой должен завершаться быстро; более долгое ожидание медленного режима не является исправлением.

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

Ожидайте ответы 200/504/502 для режимов healthy/slow/fail. Каждый ответ содержит свой идентификатор запроса в JSON и в X-Request-ID. В журнале записи request_started должны соответствовать request_complete, upstream_timeout или upstream_status. Последняя категория отдельно фиксирует ответ 503 от вышестоящей службы, тогда как вызывающая сторона возвращает 502. Обработанный сбой может иметь успешный результат выполнения, поскольку обработчик завершился штатно, даже если его HTTP-статус равен 504 или 502.

Сравните это с предоставленным примером ограничения выполнения:

cat evidence/execution-limit.json

Этот файл является специально подготовленным синтетическим учебным свидетельством, а не данными, полученными от вашего Worker. Результат exceededCpu указывает на сбой из-за ограничения выполнения; после остановки выполнения средой выполнение обработчика приложения не гарантируется. Ожидание асинхронной вышестоящей службы в этой лабораторной работе не равно расходованию времени процессора. Прежде чем рассматривать ограничения, исследуйте ресурсоёмкие вычисления или работу с запросами; не удаляйте ограничение времени и не создавайте нагрузку для имитации этого примера. В официальном справочнике ошибок описаны категории исключений и ограничений, а документация о результатах выполнения различает результат выполнения и HTTP-статус.

Запустите проверку. Она запускает изолированную среду выполнения со своей тестовой службой и собственными идентификаторами запросов, проверяет контракты успешных и ошибочных ответов и подтверждает, что синтетический заголовок Authorization не появляется в захваченных журналах приложения. Файлы журналов учащегося не являются независимым доказательством.

Проверка запросов, журналов и метрик в реальном времени

На этом шаге проверьте исправленное поведение в своей учебной учётной записи. Остановите локальную разработку и авторизуйте эту новую виртуальную машину с помощью того же ограниченного потока авторизации устройства, который использовался ранее.

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

Откройте напечатанную ссылку, введите код и подтвердите в браузере нужную учебную учётную запись. Проверьте фактические имя и идентификатор учётной записи в стандартном выводе Wrangler.

npx wrangler whoami --json

Замените YOUR_ACCOUNT_ID фактическим идентификатором. Эта обычная команда Node сохранит его в обеих конфигурациях, поэтому каждое развёртывание явно указывает владельца.

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

У тестовой службы нет общедоступной конечной точки. Скопируйте ниже фактический URL вызывающего Worker в workers.dev. Если для учётной записи требуется первоначальная регистрация поддомена, перед продолжением воспользуйтесь процедурой из раздела «Deploy Your First Cloudflare Worker».

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

Запустите читаемый поток событий в реальном времени. Перед отправкой запросов дождитесь, пока в events.log появится сообщение Connected; само наличие файла не означает готовность.

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

Найдите ожидаемые ответы 200/504/502 и соответствующие идентификаторы в оперативных журналах приложения. Если событие ещё не появилось, через несколько секунд снова просмотрите тот же журнал; не изменяйте приложение, чтобы искусственно создать событие. Если поток завершился, остановитесь и проверьте tail-errors.log. Читаемый вывод может пометить вызов с обработанным ответом 504 как Ok: это означает, что среда выполнения завершила работу, а не то, что вышестоящая служба была исправна.

В Dashboard откройте именно вызывающий Worker в выбранной учётной записи, убедитесь, что его привязка UPSTREAM указывает на эту тестовую службу, и откройте раздел Metrics. Доступные графики агрегируют запросы и ошибки вызовов и могут запаздывать после короткого теста; фиксируйте фактически отображаемые данные, не требуя немедленного ненулевого значения. Для свидетельств по отдельным запросам используйте оперативные журналы и HTTP-ответы. Обработанный ответ 504 может отображаться в данных о статусах HTTP-ответов, не считаясь необработанным исключением среды выполнения. В справочнике по метрикам объясняются агрегация и категории вызовов.

В разделе Compute → Workers & Pages откройте именно вызывающий Worker и выберите Metrics. Проверьте цепочку навигации Worker, фильтр развёрнутой версии и диапазон времени, охватывающий ваши запросы. Кнопка обновления находится рядом с выбором диапазона времени. Снимок экрана ниже сделан вскоре после синтетических запросов healthy, slow и failed-upstream; на карточках по-прежнему отображалось No data. Это допустимое наблюдение задержки аналитики, а не доказательство того, что запросы не выполнялись или исправление не сработало. Ваши имя, идентификатор версии и итоговые значения будут отличаться. Не создавайте дополнительную нагрузку только для соответствия изображению.

Worker Metrics с элементами управления версией и диапазоном времени до появления аналитических данных

Запустите проверку после авторизации. Она проверяет сведения о владельце и состояние привязки, отправляет новые независимые запросы и захватывает отдельный поток в реальном времени. Подождите примерно минуту. Недоступный или неполный поток не даёт окончательного вывода; проверьте готовность соединения и повторите попытку, но никогда не считайте отсутствие журналов признаком успеха. После успешного завершения проверки остановите поток учащегося, используя его текущий номер задачи.

jobs
kill %1

Удаление диагностических Worker

На этом шаге, сохраняя авторизацию, удалите только вызывающий компонент и тестовую службу этой лабораторной работы. Перед удалением сначала проверьте оба имени и их учётную запись; вызывающий компонент удаляйте первым.

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

При каждом совпадающем запросе имени нажмите одну клавишу y. Закреплённая версия CLI может после удаления Worker вывести диагностическое сообщение об аутентификации для устаревшей очистки KV; не расширяйте для этого разрешения и не считайте произвольные ошибки доказательством удаления. Обновите Dashboard и запустите проверку. В успешном авторизованном списке оба имени должны отсутствовать. Сохраните учётную запись, поддомен и сторонние ресурсы.

Отключение виртуальной машины

На этом шаге отключите виртуальную машину после проверки удаления ресурсов. Закрытие терминала или выход из учётной записи не удаляет облачные ресурсы.

npx wrangler logout
npx wrangler whoami --json

Ожидайте loggedIn=false; для такого неавторизованного состояния команда может завершиться с ненулевым кодом. Запустите финальную проверку. Вход в браузере и учебную учётную запись можно будет повторно использовать в следующей новой лабораторной работе.

Итоги

Вы воспроизвели необработанный тайм-аут, исправили ограниченные по времени сбои зависимости и сопоставили идентификаторы запросов в ответах и структурированных журналах. Успешное поведение сохранилось. Вы различили ошибки HTTP приложения, результаты выполнения среды и синтетические свидетельства ограничения CPU, проверили фактическое поведение в облаке, а затем удалили оба Worker и отключили виртуальную машину.