Пользователь запускает выгрузку, и в тот же момент личный кабинет перестаёт отвечать другим людям. Для Node.js это повод проверить блокировку event loop — цикла, который обслуживает события и выполняет JavaScript-обработчики. Но совпадения по времени недостаточно: похожий симптом дают база данных, внешний API и нехватка ресурсов.
Начните с трёх безопасных действий:
- Запишите, какая операция запускает задержку, когда она началась и какие соседние действия перестали работать. Не прикладывайте содержимое заказов и персональные данные.
- Сопоставьте этот интервал с уже доступными графиками времени ответа, процессора и памяти. Отметьте, какой экземпляр приложения обслуживал запрос.
- Передайте разработчику сценарий для повторения на тестовом контуре с искусственными данными и отключёнными реальными отправками.
Не повторяйте тяжёлую операцию на рабочем сайте ради доказательства. Если посетители уже сталкиваются со сбоем, сначала нужен согласованный способ ограничить проблемный сценарий и восстановить обслуживание.
Почему async не устраняет тяжёлое вычисление
По документации Node.js, длительный JavaScript-обработчик задерживает выполнение других обработчиков в том же потоке. Это может быть расчёт, обработка большого JSON или синхронная операция с файлом. Пока она не завершится, соседние запросы будут ждать своей очереди.
Объявление функции через async само по себе не переносит вычисления в другой поток. Тяжёлый цикл внутри такой функции остаётся тяжёлым; обёртка в Promise не делает его параллельным. Поэтому предложение «добавить await» ещё не объясняет, какая работа перестанет занимать основной поток.
При нескольких процессах сбой может проявляться лишь на части запросов. Общий график всего сервера способен скрыть проблему одного экземпляра, поэтому измерения нужно связывать с конкретным процессом и временем операции.
Как отделить блокировку от медленной базы или API
Ни один показатель не устанавливает причину в одиночку. Для разработчика полезна такая карта гипотез:
- Тяжёлая обработка в основном потоке. Вместе с операцией замедляется простой контрольный запрос к тому же процессу, а задержка event loop растёт. Профиль процессора показывает участок кода, который стоит исследовать.
- Ожидание базы или внешнего сервиса. Рабочий запрос медленный, но контрольный отвечает обычно; заметная часть времени уходит на зависимость. Нужно измерить ожидание соединения и выполнение запроса, прежде чем переносить код в worker.
- Синхронный вызов. Цикл задерживается, хотя процессор может быть загружен умеренно. В обработчике ищут операции, которые удерживают поток до завершения, включая синхронные файловые вызовы.
- Общее ограничение ресурсов. Растут задержки нескольких процессов, память или признаки ограничения процессорного времени. Сначала нужно отделить влияние среды и сборки мусора от стоимости конкретного обработчика.
Контрольный запрос должен быть лёгким, проходить через исследуемый процесс и не обращаться к той же медленной базе. Ответ балансировщика или другого экземпляра приложения не доказывает, что нужный event loop свободен.
Что измерить на изолированном тестовом контуре
Зафиксируйте версию приложения и Node.js, ресурсы процесса, размер искусственных данных и число одновременных операций. Сначала снимите обычное поведение без тяжёлого сценария, затем повторите его при неизменных условиях. После доработки используйте тот же набор данных и порядок действий.
В Node.js есть monitorEventLoopDelay из node:perf_hooks: он собирает распределение задержек цикла событий. Значения выдаются в наносекундах; для миллисекунд их делят на миллион. Настройки измерения и интервал наблюдения должны совпадать до и после изменения.
Разработчик сопоставляет задержку цикла с временем ответа контрольного запроса, ошибками, загрузкой процессора и длительностью самой задачи. Для редких остановок нужны также максимум и временная привязка: среднее или один перцентиль могут скрыть короткий сбой. Универсального «хорошего числа» для всех сервисов нет — предел следует из требований конкретного сценария.
Метрика eventLoopUtilization показывает занятость цикла, а не загрузку процессора. Высокое значение не доказывает, что причина именно в вычислениях. Для поиска участка кода используют профиль процессора, снятый разработчиком в согласованном тесте; сам профиль не стоит передавать наружу без проверки на закрытые сведения.
Если вопрос шире одной операции — например, сколько посетителей выдержит сайт перед акцией, — пригодится отдельный план нагрузочной проверки.
Когда нужен worker, а когда фоновое задание
Выбор зависит от того, что подтвердили измерения и когда пользователю нужен результат.
Вычисление должно завершиться в рамках обращения. Для затратного JavaScript может подойти worker_threads — выполнение в отдельных потоках. Документация Node.js рекомендует переиспользовать пул потоков: запуск нового worker на каждую небольшую задачу сам создаёт издержки. Передача больших данных тоже имеет цену, поэтому решение проверяют на характерном объёме.
Результат допустимо получить позже. Можно спроектировать фоновое задание с отдельным исполнителем. Интерфейс получает идентификатор операции и показывает её состояние; тяжёлая работа не должна возвращаться в основной обработчик веб-запросов. Очередь требует ограничений на размер и параллельность, правил повторов и понятного сообщения об ошибке.
Основное время занимает ожидание ответа. Worker обычно не ускоряет сетевой запрос. Здесь проверяют зависимость, таймауты и допустимое число одновременных обращений. А если вычисление можно безопасно разбить на короткие части, разработчик может оценить поэтапную обработку с передачей управления циклу.
«Задание принято» и «результат готов» — разные состояния. Быстрый ответ интерфейса нельзя считать исправлением, если работа потерялась, очередь бесконечно растёт или ошибка скрыта от пользователя.
Учебный пример и критерии приёмки
Допустим, тестовый сервис строит отчёт по искусственным записям, а рядом открыт простой запрос состояния кабинета. Это учебный сценарий, не описание клиентского проекта. Цель проверки — сохранить отзывчивость кабинета и получить правильный отчёт, даже когда вычисление занимает заметное время.
До изменения команда записывает условия запуска и наблюдаемую задержку. Затем проверяет выбранную реализацию на том же объёме данных: один отчёт, несколько допустимых одновременных отчётов и отказ исполнителя. Отдельно сравнивает содержимое результата с ожидаемым, а не только скорость открытия страницы.
Для задания на доработку можно использовать пять условий:
- Контрольный запрос к исследуемому процессу укладывается в согласованное время во время расчёта; ошибки также учтены.
- Результат расчёта соответствует ожидаемому, а время готовности измеряется отдельно от времени принятия задания.
- При превышении допустимой нагрузки новые задания получают понятное состояние ожидания или отказа; потребление памяти остаётся в заданных границах.
- Сбой исполнителя приводит к наблюдаемой ошибке или безопасному повтору. Повтор не создаёт второй бизнес-результат.
- После завершения нагрузки сервис возвращается к исходному режиму; повторная проверка даёт сопоставимый результат.
Все пределы и допустимые отличия согласуют до приёмки. Отчёт должен связывать исходный симптом, найденный участок, изменение и повторный тест. Формулировки «добавили очередь» или «процессор стал ниже» без этой связи недостаточны.
Где заканчивается самостоятельная проверка
Владелец проекта может собрать время сбоя, последовательность действий и уже имеющиеся графики. Если своя команда умеет воспроизвести проблему, получить профиль и проверить результат на стенде, внешний подрядчик для этого не обязателен.
Помощь уместна, когда зависание затрагивает заказы и личный кабинет, нет наблюдения за отдельными процессами или непонятно, как вынести работу и сохранить корректность повторов. OpenStart занимается диагностикой и доработкой действующих Node.js-сервисов, включая API и фоновые задачи; объём первого этапа определяется по устройству проекта.
Опишите проблемный сценарий Node.js-сервиса: какая операция запускает задержку и что перестаёт отвечать рядом. Сначала уточним стек, условия воспроизведения и критичные действия, затем согласуем первый этап диагностики. Пароли, токены и выгрузки клиентских данных для первого обращения не нужны.
Техническая основа: официальные материалы Node.js «Don't Block the Event Loop», «Performance measurement APIs», «Worker threads» и «Profiling Node.js Applications». Проверено 25 октября 2026 года.