Node.JS [ru] | Серверный JavaScript
11.2K subscribers
171 photos
7 videos
25 files
3.58K links
Node.js, backend и AI-разработка: статьи, новости, вайбкодинг, автоматизация и работа с ИИ-агентами.

Личный блог автора - @just_genych
По вопросам рекламы или разработки: @g_abashkin

РКН: https://vk.cc/cJPGOP
Download Telegram
Buffer.write со str.length — тихая бомба под production.

Ты пишешь в буфер, передаёшь offset через str.length, и данные записываются в неверное место. Всё молча. Никаких ошибок. Просто битая информация.

В UTF-8 один символ может занимать от 1 до 4 байт. «Привет» — это 6 символов, но 12 байт. Если offset посчитан по длине строки, ты фактически говоришь Buffer: «запиши мне данные со смещением 6 байт». А нужно было с 12. Разница в два раза.

Я такое видел в production: кусок бинарного заголовка перезаписывался, файл читался как мусор. И никто не мог понять, почему.

Диагностика
— используй Buffer.byteLength(str, 'utf8') для вычисления реального размера в байтах;
— сравнивай str.length и Buffer.byteLength(str) — если различаются, в строке есть не-ASCII символы;
— проверяй логи, где размер буфера и смещение не сходятся.

Исправление
Простое решение:
const byteOffset = Buffer.byteLength(str, 'utf8');
buf.write(str, byteOffset);

Или вообще запиши с начала: buf.write(str, 0, 'utf8').

Типичная ошибка
— расчёт offset вручную через str.length * someCoefficient — это антипаттерн;
— молчаливое переполнение буфера без проверки остаточного места;
— путаница между символьным и байтовым смещением в одном бинарном сериализаторе.

Профилактика
— всегда считай байты через Buffer.byteLength();
— не вычисляй offset вручную для строк с Unicode;
— в TypeScript включай strict — он ловит часть таких косяков.

Вывод:
Silent data corruption — гадость редкая, но реальная. Проверь код: не используешь ли str.length как offset для Buffer.write?
1
PROvoke на Analyst Days: как мы выступали в корсете и что из этого вышло

Привет, Хабр! В первой части я рассказывал, как мы с Татьяной Маркиной готовили доклад «Провоок» на Analyst Days — про споры, студию в Краснодаре, логистический ад и идею с кнутом и пряником. А сегодня — вторая часть: что произошло на сцене, какие роли мы играли, почему корсет так и не вышел в свет, и как один разговор в кулуарах перевернул моё понимание публичных выступлений. Подробности — во второй части статьи.

Источник: Анатомия парного доклада: как мы собирали «PROvoke» на Analyst Days. Часть 2 — выступление и фидбек
Как один отказ бизнесу сэкономил компании 10 миллионов рублей

К концу проекта внедрения нового биллинга бизнес предложил перенести архивные продукты и исторические данные по ним. Архивные продукты использовались редко — для разбора спорных ситуаций с клиентами. Изначально было решено не избавляться от старого биллинга, а использовать его для чтения ретроданных. После оценки работ выяснилось, что типового механизма нет — нужно менять архитектуру, разрабатывать сценарии миграции, тестировать и поддерживать. Оценка составила около 10 миллионов рублей. Пересчет финансовой модели показал, что дополнительные инвестиции увеличивают срок окупаемости проекта на один год. Компания вкладывала бы деньги в функциональность без измеримой бизнес-ценности. Было принято решение отказать бизнесу и предложить оставить эти данные доступными для чтения в legacy биллинге.

Источник
Гео-аналитическая платформа вдвоём за 2,5 месяца: история spec-driven разработки

Автор поделился опытом старта проекта с чистого листа. Перед ним стояла амбициозная задача, не было легаси и была полная свобода выбора подхода. Он решил максимально довериться AI и больше не трогать код. Изначально были сомнения, что такой подход выдержит реальный масштаб, так как опыт подсказывал, что чем больше проект, тем быстрее AI путается в контексте и упирается в лимиты.

Через 2,5 месяца работы вдвоём удалось запустить гео-аналитическую платформу. Автор отмечает, что в до-AI эпоху такой проект строили бы годами. Этот опыт изменил его представление о разработке.

Читать далее
Маск внезапно выкатил Grok 4.5 — первую версию, заточенную под код и агентов 😨

Обучали её в связке с Cursor, и по бенчмаркам она уже перепрыгивает GPT-5.5, заодно держится на уровне Opus 4.8. Terminal-Bench: у неё 83%, а у Opus 4.8 — 78,9%.

Прайсинг: $2/$6 за миллион токенов. «Opus-уровень, но шустрее, меньше жрет токенов и дешевле» — написал Маск в X. В Cursor она уже есть на всех тарифах. Завтра ждем ответочку от Альтмана 😊

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Грейсфул шатдаун: как SIGTERM и postMessage ломают порядок сигналов

Каждый middle/senior разработчик Node.js сталкивался с грейсфул шатдауном, но редкий замечает скрытую ловушку — смешивание process.on('SIGTERM') и Worker.prototype.postMessage. Из-за разницы приоритетов событий и микрозадач теряются данные в production.

Проблема приоритетов событий
SIGTERM — системное событие с высоким приоритетом в цикле событий. postMessage — асинхронная операция, попадающая в очередь микрозадач. Если SIGTERM приходит до завершения отправки сообщения, оно обрабатывается уже после shutdown. Результат — потеря данных, которые должны были уйти в Worker.

Production-пример и диагностика
Рассмотрим типичный код:
process.on('SIGTERM', () => {
console.log('Shutdown');
worker.terminate();
});
worker.postMessage({ type: 'data', payload: result });


Здесь postMessage может быть прерван сигналом. Как диагностировать:
* Логируйте порядок событий с таймстемпами.
* Используйте process.on('SIGTERM', { once: true }) для однократного вызова.
* Проверяйте флаг isShuttingDown перед любым postMessage.

Практическое исправление
Решение — флаги состояния:
let isShuttingDown = false;
process.on('SIGTERM', () => { isShuttingDown = true; });
if (!isShuttingDown) worker.postMessage({ ... });


Для надёжности — SharedArrayBuffer для атомарной синхронизации между основным потоком и Worker, если требуется строгий контроль.

Типичная ошибка
Многие путают: проблема не в доступе к process из Worker threads — Worker его не имеет. Корень — порядок микрозадач в основном потоке, где postMessage может быть отложен после обработки SIGTERM.

Вывод: Используйте флаги состояния перед асинхронными операциями в обработчиках сигналов — это предотвращает потерю данных при грейсфул шатдауне.
👍21
This media is not supported in your browser
VIEW IN TELEGRAM
Claude Code теперь стерильно для стаи

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

Потыкать

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
2
OpenAI наконец-то почесались и закатили апдейт: GPT-5.6 Sol, Terra и Luna — уже в проде, дружок. Постепенно раздают ранний доступ по всему шарику.

Вот пруф, если глазам не веришь

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Anthropic раскатал схему работы Fable 5 в обнимку с Sonnet 5 — тут два варианта

Первый вариант — Fable 5 втыкается как «советник» (Advisor). Sonnet 5 тащит задачу, но периодически дёргает Fable 5 за стратегическим советом. На тесте SWE-bench Pro такая связка вывозит примерно 92% от качества Fable 5, при этом платишь всего 63% от её цены. Fable 5 дёргают примерно раз на задачу. Подробнее в документации.

Второй расклад — Fable 5 работает оркестратором. Она разруливает план и раздаёт таски исполнителям — Sonnet 5. В Benchmark-тестах BrowseComp на Claude Managed Agents такая конфигурация показала 96% производительности Fable 5, а стоила 46% от оригинала. Жирные по ресурсам задачи скидывают на Sonnet 5. Пример в кукбуке.

Claude Managed Agents переваривает оба подхода (документация). Каждый подагент держит свой кэш, так что при повторных вызовах не придётся платить за полную пережевку контекста.

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🤣 Мы все ждали когда это начнётся

✖️ xCode Journal
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4
Системный аналитик — не просто почтальон между бизнесом и разрабами. Часто тащит на себе интегратора, деливери-менеджера, продакта, архитектора и даже скрам-мастера. И периодически в него летят таски, которые вообще не его профиль. Это такой челлендж: либо ты закаляешься, либо ловишь ментальный аут.

Это уже второй заход от Александра Малышева, лид-аналитика из МТС Cashback. И тут он расписывает зону ответственности SA. Всё в стихах и с юмором — прямо как народная сказка.

📖 Читать сказку

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1
Anthropic решила, что пора поживиться, и попыталась снять с парня $16,6 млн просто за красивые глаза 👻

Корейский юзер, у которого бесплатный тариф и ноль запросов к API, получил официальную бумажку с требованием оплатить $16,6 млн. А за день до этого ему же прилетел запрос на $1,6 млн — сумма за ночь выросла в 10 раз. Хорошо, что банк просто зарубил эти попытки из-за лимита карты.

Anthropic пока молчит. И это не единичный случай: на Reddit народ тоже жалуется на внезапные списания от этой конторы.

Инфа сотка 😁

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Неявная блокировка Event Loop: как MapIterator убивает производительность в hot-path

Казалось бы, обычный for...of по Map — и вдруг Event Loop начинает тормозить. Проблема в скрытой аллокации MapIterator при деоптимизации V8. В hot-path это приводит к частому GC и блокировкам.

Почему это происходит
V8 в оптимизированном коде (TurboFan) может не аллоцировать итератор — он сохраняется на стеке или убирается escape analysis. Но деоптимизация из-за полиморфизма типов ключей (строки и числа), try/catch внутри цикла или превышения inline-лимитов заставляет создавать MapIterator в куче. В production это вызывает пинг-понг с GC.

Диагностика на практике
- --trace-gc — ищем аллокации MapIterator.
- --trace-deopt — смотрим причину: часто смешение типов ключей или нестабильный полиморфизм.
- Сравни for...of, map.forEach и ручной обход через Array.from(map.keys()) в бенчмарке. Разница может быть кратной.

Практический совет
В hot-path используй forEach, а не for...of. V8 может встроить его колбэк и избежать аллокации итератора. Если нужны ключи — закешируй их через Array.from и обходи обычным циклом.

Типичная ошибка
Не проверяешь стабильность типов ключей Map. Если ключи смешанные (строки и числа) — for...of гарантированно деоптимизируется. Зафиксируй типы или используй forEach.

Вывод: Аллокация MapIterator в hot-path из-за деоптимизации V8 — скрытая причина лагов Event Loop; замена for...of на map.forEach или кеширование ключей через Array.from устраняет проблему без ущерба для читаемости.
2
Заглянули под капот ChatGPT

Парень, который копался в производительности Linear, потратил несколько дней на изучение сорцов, бандлов и запросов к ChatGPT. Внутри — React Router 7, TanStack Query, Radix и ProseMirror. Вся ненужная хрень грузится только когда юзер начинает долбить по клавишам.

Base UI теперь рулит в shadcn/ui по умолчанию — свежие проекты стартуют на Base UI, а не на Radix. Radix пока не выкинули на помойку, оба набора компонентов доступны. Но для нового говна рекомендуют Base UI.

Shadcn подвезли переводы без передеплоя — облачный бэкенд от команды i18next с функциями saveMissing, редактированием в контексте, AI-переводом и мгновенными апдейтами через CDN. Есть бесплатный тариф, делают в Швейцарии.

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
К 2013 году американская журналистика уже пятый год лежала на лопатках. Кризис 2008-го вынес рекламную модель прессы: в газетных ньюсрумах США осталось меньше половины сотрудников, десятки тысяч спецов остались не у дел. Потерявшие работу журналисты ушли на фриланс. Параллельно с этим университетские программы по научной журналистике (MIT, Нью-Йоркский, Санта-Круз) стабильно штамповали новых выпускников. И третий поток — учёные, свалившие из академии (постдоки, не получившие должность).

Итог: три потока продавцов и дохлый ручеёк покупателей. У Science или Smithsonian — 10-20 заказов на фриланс в месяц, заявок — десятки в день.

Источник: Хабр

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
structuredClone и Error с глубоким стек-трейсом: неявный убийца производительности в worker_threads

Передаёте Error через worker.postMessage()? Если стек-трейс глубокий — после цепочки асинхронных вызовов — V8 может незаметно блокировать поток на сериализации. Производительность падает линейно, а вы ищете причину в другом месте.

Почему это происходит

При вызове structuredClone V8 сериализует все перечислимые свойства объекта, включая .stack. Для Error с сотнями фреймов (длинные URL, аргументы функций) V8 парсит стековую строку целиком. Каждый фрейм проверяется, разбирается — и это происходит синхронно в вызывающем потоке. Пример: 5000 повторений .stack через repeat дают задержку ~100ms на postMessage.

Как диагностировать

Используйте --trace-event-categories или clinic flame. Ищите пики CPU в structuredClone. Сравните время postMessage с простым объектом против Error — разница в 10-50 раз при глубоком стеке. Типичная ошибка: разработчики грешат на дорогие вычисления, а на самом деле V8 тупо сериализует строчку.

Решение: не передавайте полный Error

Клонируйте только критичные поля: message, code, line, fileName. Для огромных стеков передавайте идентификатор ошибки, а полный стек собирайте локально. Можно упаковать Error в простой объект:

const safeError = {
message: err.message,
code: err.code,
line: err.stack?.split('\n')[1]
};
worker.postMessage(safeError);


Production-кес: в нашем сервисе 20% CPU уходило на structuredClone ошибки с 1500+ фреймами. После замены на { msg: err.message } блокировка исчезла полностью.

Вывод: Не передавайте полный Error между воркерами при глубоких стеках — сериализация через structuredClone может незаметно съедать 10-20% CPU и блокировать поток.
👍1
Reverse Engineering ChatGPT Web — чувак, который когда-то разбирал Linear по косточкам, решил не останавливаться и вдумчиво покопался в исходниках ChatGPT. Он прошерстил бандлы, запросы и нарыл там React Router 7, TanStack Query, Radix и ProseMirror. Фишка в том, что весь ненужный хлам не грузится, пока ты не начнешь стучать по клавиатуре.

Base UI теперь рулит в shadcn/ui — новые проекты на shadcn/ui едут на Base UI, а не на Radix. Радикс не умер, компоненты доступны для обеих платформ, но для свежих проектов советуют именно Base UI.

TypeScript 7.0 — выкатили компилятор на Go, который шпарит в 10 раз быстрее. Правда, без нормального API от версии 6.0 пока что его рекомендуют кучке фронтенд-фреймворков.

Vercel пригрела команду Better Auth — той самой популярной либы для аутентификации.

React Navigation 8.0 — ребята делятся успехами, в том числе навигацией с поддержкой Suspense.

Next.js — опубликовали официальный RFC для WebSocket в Route Handlers.

npm v12 — теперь жизненные циклы скриптов и сборки node-gyp по умолчанию не запускаются.

Подробнее — в выпуске React Status #482.

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
1