DevNotes Live
6 subscribers
84.1K photos
12K videos
195 files
35.3K links
Автоматический агрегатор IT ресурсов в Telegram (@devnotes_robot)
Информация: https://t.me/devnotes_live/121
Download Telegram
Forwarded from Daily Coding 🔥
🛠 pitrery - это набор инструментов для упрощения управления резервными копиями и восстановлениями PITR

🌍 Сайт

Daily Coding #инструменты #SQL & Max
WebSocket backpressure в Node.js: когда ws.send() без контроля ведёт к OOM

Игнорирование скорости потребления данных клиентом при push-рассылках — одна из частых причин падения Node.js-процесса из-за нехватки памяти. Проблема кроется в том, что библиотека ws буферизует неотправленные фреймы в очереди, которая растёт линейно при медленных или спящих клиентах.

Через bufferedAmount
Каждый сокет библиотеки ws имеет свойство bufferedAmount, показывающее количество байт в очереди на отправку. Перед вызовом ws.send() проверяйте порог. Если он превышен — пауза отправки.
if (ws.bufferedAmount > 1_000_000) {
ws.pause();
}


Событие drain
После освобождения буфера сокет генерирует событие drain. Его можно использовать для возобновления отправки, выстраивая собственную очередь с контролем размера.
function sendOrQueue(ws, data) {
if (ws.bufferedAmount > 0) {
ws.once('drain', () => ws.send(data));
} else {
ws.send(data);
}
}

Типичная ошибка — навешивать drain на каждый send() без очистки предыдущих обработчиков. Это приводит к утечкам слушателей.

Собственная очередь с лимитом
Если число неотправленных сообщений превышает лимит, отключайте клиента через ws.terminate(). Иначе память растёт неконтролируемо.
const MAX_QUEUE = 2000;
if (ws.bufferedAmount > MAX_QUEUE * 1000) {
ws.terminate();
return;
}

В production при push-рассылках на 10 тысяч клиентов с bufferedAmount > 1 MB каждый, процесс потребляет 10+ GB RAM и падает с OOM.

Мониторинг
Логируйте клиентов с bufferedAmount > 512 KB. Это ранний индикатор проблем. В библиотеке ws до версии 8.x отсутствовал встроенный контроль потока, а net.Socket использует backpressure через write() + drain, но ws его не учитывает по умолчанию.

Вывод: Проверяйте bufferedAmount, используйте drain и задавайте жёсткие лимиты очереди — иначе незаметный OOM гарантирован при любой расходящейся нагрузке.
Странные визуализации: диаграммы меридианов

К концу книги Виллема тен Рэйне (1647–1700) «De Acupunctura» нидерландский врач рассказывает о том, что, по-видимому, было первым случаем, когда он увидел выполнение процедуры иглоукалывания.
https://archive.org/details/BIUSante_71050/page/n214/mode/1up

Он находится на корабле вместе с императорским японским солдатом во время hofreis — тысячекилометрового путешествия из Нагасаки ко двору императора в Эдо. Солдат страдает от морской болезни, а возможно, и от излишней любви к удовольствиям. Есть только одно решение, и он выполняет его сам:

В моём присутствии он выполнил иглоукалывание следующим образом (на основании этого случая, читатель, суди и о других). Лёжа на спине, он вонзил иглу в левую сторону живота выше привратника желудка в четырёх разных местах. (Для этого он осторожно держал остриё иглы кончиками пальцев.) Пока он постукивал по игле молотком (поскольку его кожа была довольно жёсткой), он задерживал дыхание. Когда игла вошла примерно на ширину пальца, он повернул её рукоятку. Затем он прижал пальцами место укола. После извлечения иглы крови, однако, не появилось; остался лишь едва заметный след от прокола. Освободившись от боли и излечившись этой процедурой, он восстановил здоровье.


Для европейского врача XVII века, чьё гиппократовское образование всё ещё опиралось на учение о жидкостях организма, отсутствие крови при процедуре, вероятно, было не меньшим удивлением, чем всё остальное. Молоток, который использовал солдат, был японским нововведением в почти двухтысячелетней китайской традиции иглоукалывания.

Тен Рэйне сразу же взялся выяснить, как это работает. «De Acupunctura» — сильно аннотированный перевод китайского руководства по иглоукалыванию, включающий пять гравюр на меди (первые две — китайские точки акупунктуры, две — японские, и одна — изображение иглы и молотка) — стала его попыткой донести эту мудрость до Европы.
Почему пользователи лучше воспринимают детали через компактные окна, выезжающие в режиме slideover

Статья рассказывает о плюсах и минусах полностраничных и компактных окон в дизайне интерьера. Узнай, как выбрать подходящий вариант для своего помещения

Читать на дизайнерс | #статья
Forwarded from Vladimir Alyamkin
Умеет программировать? Да — технарь-программист
Умеет рисовать? Да — артист/художник

Оба ответа нет? Техарт!
Forwarded from Daily Coding 🔥
🛠 Faker - быстро вставляйте данные-заполнители, используя популярную JavaScript-библиотеку Faker. Вы можете генерировать случайные имена, адреса, изображения, номера телефонов или просто абзацы из классической Lorem Ipsum. Каждая категория имеет различные подкатегории, чтобы вы могли адаптировать данные к своим потребностям.

🌍 Сайт

Daily Coding #инструменты #JavaScript & Max
Утечка памяти, которую вы не заметите: rejections в for await...of и стримы

Обработка ошибок в асинхронных итераторах и стримах кажется интуитивной, но неочевидные rejections внутри генератора или метода _read() могут привести к зависанию итерации и неосвобождению памяти. В production это проявляется как постепенный рост heap-usage без видимых причин.

Почему это происходит?
Когда вы используете for await...of, движок ожидает объект { value, done } от итератора. Если внутри асинхронного генератора возникает rejection (например, от необработанного промиса), итерация может зависнуть в бесконечном ожидании, а буферы стрима или данные генератора останутся в памяти.

Пример с генератором:
async function* gen() {
yield 1;
await Promise.reject(new Error('fail'));
yield 2; // не достигнется
}
for await (const v of gen()) { } // зависнет?

Хотя ошибка пробросится, внутренние ресурсы — открытые соединения, таймеры — могут остаться висеть.

В стримах ситуация опаснее:
const { Readable } = require('stream');
const stream = new Readable({
async read() {
const data = await riskyOp();
this.push(data);
// если rejection без this.destroy() - утечка
}
});
for await (const chunk of stream) { }

Если read() не завершится вызовом this.destroy(err), стрим не сгенерирует событие 'error' и не очистит внутренний буфер.

Практические советы:
* Всегда обрабатывайте rejections через try-catch внутри итератора и явно завершайте итерацию — throw или return.
* Для стримов используйте this.destroy(err) при ошибках в _read или предпочтительно pipeline для автоматической обработки.
* Добавьте finally для гарантированной очистки ресурсов (закрытие соединений, таймеров).
* Проверяйте утечки через heap snapshots или process.on('warning') — не стесняйтесь мониторить.

Вывод: for await...of не обеспечивает автоматической очистки, и необработанные rejections — прямой путь к утечке памяти, поэтому всегда завершайте итерацию явно.
Городские пейзажи в коллажах от Andy Burgess
This media is not supported in your browser
VIEW IN TELEGRAM
Немного психоделической анимации от студии из Копенгагена Outlanders.

#анимация