N
Node.JS [ru] | Серверный JavaScript
17.07.2026 13:07 · 👁 321
Диагностика неявного deadlock в async_hooks при IPC в Node.js кластерах
Вы сталкивались с ситуацией, когда кластеризованное Node.js приложение потребляет 100% CPU без видимых ошибок, а event loop замирает? Часто причина — неявный deadlock в async_hooks, возникающий при смешивании синхронных IPC-вызовов через child_process.send и MessagePort.close в воркерах.
Гонка за ресурсами IPC
send() в child_process синхронно блокируется до отправки данных. Если следом вызвать port.close(), возникает замыкание: send() удерживает IPC-ресурс, close() ждет его освобождения, а async_hooks зависает в состоянии "ожидания завершения". Результат — ресурсы не освобождаются, ошибок нет, CPU занят вхолостую.
Production-пример: кластер с обработкой запросов, где каждый воркер отправляет результат через send и закрывает порт. После пары тысяч запросов — deadlock, все воркеры зависают.
Диагностика
Чтобы отловить проблему, включите логирование async_hooks с таймстампами:
- init для IPC-каналов появляется
- destroy приходит с задержкой или отсутствует вовсе
- No errors in logs
Практический совет: исправление
Замените синхронный send на асинхронный. Плохой паттерн:
send({ data }, (err) => { port.close(); });
Хороший паттерн:
await new Promise(resolve => process.send({ data }, resolve));
port.close();
Используйте MessageChannel вместо child_process.send — он избегает блокировки. Если deadlock уже произошел, убивайте воркер через worker.kill(), а не process.exit().
Профилактика
- Ставьте timeout на все IPC-операции
- Мониторьте async_hooks метрики через performance hooks
- Гоняйте кластер под нагрузкой с логированием ресурсов
Вывод: Синхронный IPC-вызов с последующим закрытием порта создает неявный deadlock в async_hooks, который проявляется только как 100% CPU и зависший event loop — переходите на асинхронные паттерны для всех межпроцессных коммуникаций.
N
Node.JS [ru] | Серверный JavaScript
17.07.2026 09:07 · 👁 476
Point0 — очередной фулстек-фреймворк, который уже успели обозвать конкурентом tRPC. Судя по описанию, DX тут реально похож: те же квери и мутации. Но Point0 идет дальше — позволяет объявлять запросы прямо в клиентских файлах вместе с серверной логикой, сам шарит за гидрацию и дегидрацию при SSR, умеет швырять файлы через FormData, выдает стабильные урлы для эндпоинтов и может отдавать серверные компоненты или интерактивные острова.
Плюс фреймворк не кладет редактор мордой в стол, когда эндпоинтов становится дофига, и нормально рулит состояниями загрузки. Автор предполагает, что ты уже шаришь за tRPC — так что в статье накидали примеров на нем для сравнения.
Читать далее
👉 Node.JS [ru]
N
Node.JS [ru] | Серверный JavaScript
17.07.2026 06:07 · 👁 507
Как получить оффер в Яндекс, Сбер, МТС и другие крутые компании?
На фото ребята из моего комьюнити, где уже больше 220 frontend-разработчиков. Все они успешно устроились в крутые компании и получили офферы от 300 тыс рублей 🫂
👋 Привет, меня зовут Тихон, я действующий Frontend-разработчик и ментор. За руку довожу до оффера в Big Tech и остаюсь рядом на испытательном сроке.
В их жизни больше нет бесконечных скучных созвонов, безуспешных откликов на вакансии, странноватых собесов с вопросами словно ты на олимпиаде.
И у тебя тоже получится 😎
У меня есть канал, где я:
👉 Показываю, как пройти HR-фильтр и превратить отклики в реальные приглашения
👉 Помогаю найти мотивацию и разбираюсь с убеждениями, которые мешают расти
👉 На примерах показываю, как проходить собеседования, включая техничку
👉 Разбираю резюме и делюсь лайфхаками — например, как аккуратно «пинговать» рекрутеров
И регулярно выкладываю полезное:
▪️ Задачи, на которых валятся кандидаты
▪️ Подборка из 100+ каналов с вакансиями для разработчиков
▪️ 100 вопросов, которые помогут тебе на собеседовании
▪️ Чек-лист для проверки своего резюме
Подписывайся: https://t.me/+KcX6eD0fuRY3M2Uy
Реклама, erid: 2W5zFJKcvZP ИП Галактионов Тихон Витальевич, ИНН 771618975809
N
Node.JS [ru] | Серверный JavaScript
16.07.2026 17:07 · 👁 621
MinIO, MongoDB, PostgreSQL для хранения 25 лет истории стоимости акций
💾 Когда ты строишь эмулятор для проверки торговой стратегии — 20 акций, 25 лет поминутных данных — выбор хранилища превращается в головную боль архитектурного уровня.
Автор раскурил, почему MinIO тут не взлетел, где MongoDB уперлась в потолок, и как PostgreSQL с Pgpool-II и read-репликами срезал время чтения свечи с 40мс до 10мс.
Читать далее: https://habr.com/ru/articles/1059062/
👉 Node.JS [ru]
N
Node.JS [ru] | Серверный JavaScript
16.07.2026 14:47 · 👁 597
Просто показываем промокод
Просто предлагаем съездить отдохнуть со скидкой 5000 рублей от Яндекс Путешествий. Больше ничего от вас не хотим, потому что понимаем, что сил нет.
Забронировать
#реклама
travel.yandex.ru
О рекламодателе
N
Node.JS [ru] | Серверный JavaScript
16.07.2026 13:07 · 👁 518
Неявное зависание Promise.all при отмене AsyncIterator через AbortController
Вы используете for await...of с асинхронным генератором и AbortController для отмены. Кажется, всё чисто, но Promise.all зависает намертво. Проблема в том, что вызов abort() вызывает return() генератора, но если внутри остался незавершённый промис (таймер, подписка, поток), он просто висит, и Promise.all никогда не завершится.
Как возникает утечка
Когда abort() срабатывает внутри for await...of, итератор завершается. Но если в генераторе есть запущенный, но не завершённый setInterval, await на потоке данных или подписка на событие, этот промис остаётся висеть в памяти. Например, генератор каждую секунду отправляет данные, а при abort обработчик завершает итерацию, но не очищает таймер. Promise.all ждёт этот таймер вечно.
Диагностика на практике
Добавьте в конец return() генератора console.log('return called'). Если return вызывается, а Promise.all не завершается — ищите, какой ресурс утекает. Используйте обёртку с таймаутом: Promise.race([Promise.all(...), AbortSignal.timeout(5000)]). В продакшне это спасёт от вечного ожидания, но не решит корень проблемы.
Совет по исправлению
Всегда оборачивайте тело асинхронного генератора в try/finally. В finally явно очищайте все ресурсы: удаляйте слушатели, отменяйте таймеры, разрешайте ожидающие промисы. Например, если внутри генератора есть setInterval:
async function* gen(signal) {
const timer = setInterval(() => {}, 1000);
try {
while (!signal.aborted) {
await new Promise(r => setTimeout(r, 100));
yield data;
}
} finally {
clearInterval(timer);
}
}
Вывод: Каждый yield и await в асинхронном генераторе должен быть гарантированно завершён до конца итерации, иначе return() не прервёт внутренние промисы, что приведёт к невосстанавливаемому зависанию.
N
Node.JS [ru] | Серверный JavaScript
16.07.2026 09:07 · 👁 600
npm 12, TypeScript 7.0 и Bun на Rust
Выкатили npm 12 — install-скрипты теперь выключены по дефолту. Сломов дофига, так что сперва лучше проапгрейдиться до 11.18.0. GitHub
Финальный TypeScript 7.0 — на Go и «в 10 раз быстрее». Но полный API пока не докрутили, поэтому многие советуют пока не слезать с 6.0.
Bun переехал с Zig на Rust — автор выкатил полный репортаж о том, как портировал рантайм. Кучу инстансов Claude Code припахали, суммарно сожгли ~$165k по API-ценам. Rust-версия станет базой для Bun 1.4, его ждут с часу на час. Jarred Sumner
Node.js 26.5.0 — заимпортили текстовые файлы в ES-модулях через import attributes и blob.textStream().
👉 Node.JS [ru]
N
Node.JS [ru] | Серверный JavaScript
16.07.2026 07:48 · 👁 612
Бесплатный курс: веб-дизайн, графика, интерфейсы
Получи востребованные навыки:
- создание дизайна сайтов и приложений
- создание инфографики и карточек для маркетплейсов
- работа в графическом редакторе Figma и др.
Студенты курса в среднем зарабатывают от 68 000 ₽ уже во время обучения💰
Зарегистрироваться
#реклама 16+
ydaev.ru
О рекламодателе
N
Node.JS [ru] | Серверный JavaScript
15.07.2026 18:21 · 👁 642
Виртуальные Scroll-контейнеры
Йо, народ. Сегодня заценим инструмент ng-virtual-scroll-view. В прошлый раз я раскатывал про универсальные виртуализированные списки, которые внутри юзали одноосевой виртуальный scroll-контейнер. Решил из проекта ng-virtual-list выковать еще одну штуку — двухосевой виртуальный scroll-контейнер ng-virtual-scroll-view. Поддерживает Angular с 14 по 22 версии. API и примеры использования — в документации. Читай дальше
👉 Node.JS [ru]
N
Node.JS [ru] | Серверный JavaScript
15.07.2026 13:07 · 👁 555
Неявный рассинхрон состояния при AsyncLocalSnapshot, EventEmitter и Symbol.asyncDispose
Работаете с распределёнными очередями задач? Тогда наверняка сталкивались с AsyncLocalStorage для проброса контекста. Но связка AsyncLocalSnapshot с EventEmitter и забытый Symbol.asyncDispose приводят к багу, который воспроизводится раз на 50 запусков — контекст устаревает, состояние утекает.
Почему контекст утекает
AsyncLocalSnapshot замораживает контекст при создании, но колбэк от EventEmitter может жить дольше задачи. Если слушатель не удалён, он выполняется с устаревшим состоянием. В production это даёт stale data — задача обрабатывается с контекстом предыдущей или undefined.
Production-пример ошибки
Типичный сценарий: воркер запускает задачу, подписывается на события прогресса через emitter.on, но не чистит слушатель. В итоге в следующей задаче AsyncLocalSnapshot возвращает старый контекст. Код:
const snapshot = new AsyncLocalSnapshot(als);
emitter.on('event', snapshot.run(data => {
console.log(als.getStore()); // устаревший контекст
}));
// Слушатель не удалён — баг
Типичная ошибка
Забывают реализовать Symbol.asyncDispose для временных слушателей. Или создают снапшот вне обработчика, вместо того чтобы делать это внутри. Совет: всегда используйте try/finally для очистки подписок.
Практический совет
Для долгоживущих слушателей не используйте AsyncLocalSnapshot — сохраняйте контекст в замыкании. Если нужно, чистите через finally или Symbol.asyncDispose:
class Worker {
async [Symbol.asyncDispose]() {
emitter.removeAllListeners('progress');
}
}
Вывод: Управляйте временем жизни подписок явно — AsyncLocalSnapshot это моментальный снимок, а не долгоживущий контекст.