Punch2027: Tinubu will win by landslide — KaluThe Jerusalem Post32 years after AMIA attack: Monument in honor of victims to be erected in BinyaminSky TG24Oroscopo del 10 novembre, scopri cosa ti riservano gli astriInquirerWitness says Manases Carpio’s Davao lot in VP’s SALN한겨레이틀내 트럼프 2기 첫 내각 탄핵 표결…야당 우위 의회 ‘예고편’CNN TürkGalatasaray'dan Leroy Sane kararı! İşte ayrılık şartıNOSWekdienst 10/11: Onderhandelingen in Abu Dhabi • Kamer discussieert over blastingplanWirtualna PolskaFidesz Orbana na dnie. Nowy sondaż obnaża skalę zapaściSouth China Morning PostHong Kong civil servants to be given 12 hours of family care leave a yearThe Sydney Morning HeraldPM announces tougher AI protection to curb mounting risksSportstarIndia vs UAE, Under-19 Asia Cup LIVE score: Raichandani, Sehwag open; IND 36/0 (7)سكاي نيوز عربية"بحر الصداقة" يجمع مصر وتركيا.. فهل تتراجع خلافات المتوسط؟
The Daily Newsstand · Free, Always
Tuesday, November 10, 2026

[Перевод] Почему мой Mac не загружался, хотя на диске было свободно 264 ГБ?

Translate

Уже второе утро Mac зависал при загрузке. Индикатор доходил почти до конца и замирал. Я подумал, что закончилось место на диске. В режиме восстановления выяснилось обратное: свободны были 264 ГБ.

Причина оказалась во временном каталоге. За 16 часов ночные тесты оставили там 30 182 папки и 1 378 905 файлов. Сколько из них нужно, чтобы сломать загрузку macOS, я не знаю. Но с этим каталогом мой Mac не загружался, а после его очистки загрузился.

Где лежали эти файлы

На моём Mac os.tmpdir() указывал не на привычный /tmp, а на пользовательский каталог вида /private/var/folders/<xx>/<hash>/T. Документация Node.js описывает os.tmpdir() как путь к системному временному каталогу; на него также может влиять переменная TMPDIR. Поэтому путь, который возвращает функция, лучше проверять на конкретной машине.

В режиме восстановления я разблокировал том с данными, отвёл старые временные каталоги в сторону и после успешной загрузки посчитал содержимое папки T:

Источник

Папок

Файлов

Временные файлы моих тестов

25 299

1 189 858

Временные каталоги Vitest

4 603

151 679

Приложения и система

280

37 368

Всего

30 182

1 378 905

Все эти файлы появились между 23:00 воскресенья и 15:00 понедельника. Основную массу дали несколько типов тестовых каталогов: construct-detach-* — около 246 тысяч файлов, construct-attach-* — около 234 тысяч, ghosts-preflight-test-* — ещё около 113 тысяч.

Первая попытка исправления сделала хуже

Сначала я в режиме восстановления переименовал var/folders и tmp в каталоги с суффиксом .old, затем создал пустой tmp. Я хотел убрать накопившиеся файлы с пути загрузки, сохранив старые каталоги для разбора. После перезагрузки Mac попал в цикл и по-прежнему не запускался.

Вот команды той неудачной попытки; пути относятся к моему тому данных в Recovery:

mv /Volumes/Data/private/var/folders /Volumes/Data/private/var/folders.old
mv /Volumes/Data/private/tmp /Volumes/Data/private/tmp.old
mkdir -m 1777 /Volumes/Data/private/tmp

Я упустил родительский каталог /private/var/folders. В моём случае macOS создавала пользовательские папки внутри него, но не восстановила сам каталог после переименования. Пришлось снова зайти в режим восстановления, создать пустой /private/var/folders и вернуть ему владельца root:wheel и права 755. После этого система загрузилась.

mkdir /Volumes/Data/private/var/folders
chown root:wheel /Volumes/Data/private/var/folders
chmod 755 /Volumes/Data/private/var/folders

Это важная деталь именно этой истории: перенос системного каталога без восстановления его родительской структуры добавил мне вторую неисправность поверх первой.

Откуда взялось почти полтора миллиона файлов

Ночью агенты запускали тесты параллельно в разных git worktree. Каждый отдельный прогон выглядел нормально. Вместе они многократно повторили утечку временных файлов.

Часть тестов создавала каталог через mkdtempSync:

const dir = mkdtempSync(join(tmpdir(), 'construct-detach-'))

Сам вызов создаёт каталог и возвращает его путь. Удаление нужно организовать отдельно. В тестах его не было. Один каталог легко не заметить; тысячи прогонов оставили 25 299 каталогов только от наших тестовых фикстур.

Я уже внёс исправление: каждый запуск получал собственный корневой каталог вида mkr-<pid>-XXXXXX, а TMPDIR указывал внутрь него. В конце запуска корень удалялся. Изменение попало в main в 00:50 понедельника, но утечка прекратилась только около 04:00.

Причина задержки — старые worktree. Они были созданы до исправления и продолжали выполнять прежний код. Когда я проверил их, два ещё не были обновлены. Правка в main сама по себе не меняет уже запущенные ветки.

Оставался второй источник: Vitest 5.0.0. В моих запусках он создавал временную папку при старте, до того как обёртка переназначала TMPDIR. Если процесс успевал нормально завершиться, внутреннее удаление убирало папки проектов, но корневая папка оставалась. Я воспроизвёл это на одном тестовом файле: после запуска в пустом временном каталоге появилась новая папка. Таких папок накопилось 4 603; они продолжали появляться примерно по 40 в час.

Что я изменил после разбора

Я меняю запуск Vitest: он должен проходить через ту же обёртку, что и остальные процессы, чтобы TMPDIR указывал внутрь каталога запуска ещё до старта тестового раннера. Тогда временные файлы будут удаляться вместе с этим каталогом.

На случай прерванных запусков я расширяю процесс очистки: он должен находить осиротевшие каталоги и оставленные Vitest папки старше часа. Добавляю lint-правило, которое запретит прямое создание временных каталогов через mkdtempSync(join(tmpdir(), …)) в тестах: для них предусмотрен каталог конкретного запуска. Старые worktree нужно обновлять или удалять, иначе они снова запустят код с утечкой. Поведение Vitest я также планирую описать в issue проекта.

Все мои обычные индикаторы тогда были зелёными: свободное место и память оставались в норме. Я не считал количество файлов во временной папке. После этого случая для меня у каждого созданного файла должны быть понятны владелец, срок жизни и способ удаления, который можно проверить. Путь из tmpdir() сам по себе ничего из этого не гарантирует.

Источники

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.