Files
portal/tools/night/disk.mjs
T
Дмитрий 6d095d582c fix: шесть дыр из ворот К2 в правилах ночи — замок, сравнение путей, потерянные пороги, единый час, враньё про полночь, день обновления
1. Битая карточка прогона больше не считается отсутствующей: readRuns различает файл-нет и файл-есть-но-не-читается через readJsonOrBroken, и на нечитаемой карточке замок ЗАКРЫТ. Раньше порванный run.json молча выпадал из списка — замок открывался ровно в ту ночь, когда кончилось место.

2. samePath у замка сведён к поведению samePlanPath у печати через resolve: полный путь владельца и путь от корня хранилища от сторожа теперь один файл. Замерено: lefthook 2.1.8 подставляет staged_files путём ОТ КОРНЯ хранилища.

3. Потерянная настройка больше не читается как можно: нет disk_free_min_gb — отказ; нет hours_limit — hoursLimitHit падает громко, а checkSelfLimits гасит работника с названной причиной.

4. Дорога к московскому часу правда одна: limits берёт час у budget.moskovskoeVremya, своего Intl там больше нет.

5. Запись про полночь-как-24 переписана по замеру: этот Node отдаёт 00. Подчистку сторожит прямая проверка normalizeMskHour, а не случайная зелень.

6. Отказ по запасу без дня обновления и с бессмысленной датой от невиданного прибора теперь виден как сбой, а не как нормальный ответ: renewalDay плюс поле renews_on_problem.

Каждая починка накрыта проверкой, краснеющей при её вырезании. Проверок в четырёх файлах 155, было 108. Полный набор tools: 619 зелёных в 31 файле.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 02:29:40 +03:00

53 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Свободное место на диске. Замер — родным `statfs` Node (есть с 18-й версии),
// без вызова внешних программ: они на Windows зависят от локали и языка системы.
//
// 🪤 Ноль почти всегда сбой, а не правда о мире. Не удалось замерить — отдаём `null`,
// и `null` означает ЗАПРЕТ. «Наверное хватит» — это то, чем семь работников загоняют
// сервер в ноль за одну ночь: composer install и два npm ci на каждого.
import { statfs } from 'node:fs/promises';
export async function freeGb(path) {
try {
const s = await statfs(path);
return (s.bavail * s.bsize) / 1024 ** 3;
} catch {
return null;
}
}
export function diskState(free, minGb) {
// 🔴 ПОРОГА НЕТ — ЭТО НЕ «МОЖНО». Раньше эта ветка отсутствовала, и потерянная настройка
// `disk_free_min_gb` снимала правило целиком, молча и зелено: `50 <= undefined` — ложь,
// значит место пропускало что угодно, вплоть до нуля свободных гигабайт. Ровно то, от чего
// лечит девиз этого файла: ноль почти всегда сбой, а не правда о мире.
// Вырежи эту ветку — покраснеет «порога не дали».
if (typeof minGb !== 'number' || !Number.isFinite(minGb)) {
return {
ok: false,
free_gb: typeof free === 'number' && Number.isFinite(free) ? free : null,
min_gb: null,
reason: 'Порог свободного места не задан (в night.config.json потеряна настройка disk_free_min_gb) — '
+ 'сравнивать не с чем. Работать без порога нельзя: «наверное хватит» и есть тот случай, '
+ 'когда сервер уходит в ноль за одну ночь.',
};
}
if (typeof free !== 'number' || !Number.isFinite(free)) {
return {
ok: false,
free_gb: null,
min_gb: minGb,
reason: 'Свободное место замерить не удалось — работать вслепую нельзя.',
};
}
// Ровно порог — уже нельзя: порог это черта, а не «можно до неё».
if (free <= minGb) {
return {
ok: false,
free_gb: free,
min_gb: minGb,
reason: `На сервере кончается место: свободно ${free.toFixed(1)} ГБ при пороге ${minGb} ГБ.`,
};
}
return { ok: true, free_gb: free, min_gb: minGb, reason: null };
}