#Симптомы и условия возникновения
Ошибка EMFILE: too many open files означает, что процесс достиг ограничения открытых файловых дескрипторов. В Node.js она часто появляется при слишком большом числе одновременных fs-операций, незакрытых потоков или сокетов. Для начала проверьте используемую версию среды и точный текст ошибки на копии проекта, не меняя рабочий сервер.
#Причины и как их отличить
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Тысячи одновременных операцийВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | После Promise.all с чтением каталога ошибка воспроизводится сразу | Ограничить параллельные задачи. |
| Не закрываются файловые потокиВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | Число fd растёт после каждого задания | Обеспечить close/destroy и обработку error. |
| Низкий лимит службыВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | В интерактивной оболочке работает, под systemd нет | Сверить LimitNOFILE службы, менять только обоснованно. |
#Пошаговая диагностика и решение
- 1. Найдите точный стек EMFILEОткройте лог приложения и выпишите путь файла и вызов fs.open/readFile/createReadStream. Код
ENFILEотносится к общесистемному лимиту, аEMFILE— к процессу; смешивать их не следует.
- 2. Проверьте фактическое число дескрипторовВ Linux в отдельном терминале от владельца службы получите PID и посмотрите число элементов
/proc/PID/fd. Если доступ запрещён, попросите администратора выполнить диагностику. Не закрывайте чужие fd вручную. - Linux: замените PID на существующий идентификатор процессаLinux · Терминал (Bash)КомандаLinux: замените PID на существующий идентификатор процесса. Число растёт при утечке или высокой параллельности.
ls /proc/PID/fd | wc -l
- 3. Сверьте лимит процесса с systemdПроверьте
/proc/PID/limitsилиsystemctl show имя.service -p LimitNOFILE; это только чтение. Если у разных запусков лимиты отличаются, служба может иметь меньший предел. - Linux, замените PIDLinux · Терминал (Bash)КомандаLinux, замените PID. Найдите строку Max open files.
cat /proc/PID/limits
- 4. Ограничьте количество одновременных чтенийНайдите
Promise.all(files.map(...))на тысячи файлов. В тестовой копии замените безлимитный запуск на очередь с небольшим количеством работников (например, 8), увеличивайте значение по результатам замеров.
- 5. Корректно закрывайте ресурсыДля
fs.promises.openпоместитеfileHandle.close()в finally; при работе с потоками добавьте обработчики error/close и дождитесь завершения. Если утечка в библиотеке, проверьте исправления производителя, не редактируйте файлы в node_modules вручную.
- 6. Повторите наблюдение после исправленияЗапустите одинаковый набор файлов на тестовой копии. Число fd во время работы должно ограниченно колебаться и возвращаться к базовому значению после окончания.
- 7. Изменяйте лимит только как последнюю меруЕсли расчёт параллельности показывает обоснованную потребность, администратор может настроить LimitNOFILE для конкретной службы и перезапустить в окно обслуживания. Увеличение лимита не устраняет утечку.
- Пример кода по темеТекстБезопасный пример закрытия файлового дескриптора в тестовом каталоге: заранее создайте небольшой test.txt. Для файла .mjs.
import { open } from 'node:fs/promises'; const handle = await open('./test.txt', 'r'); try { const content = await handle.readFile({ encoding: 'utf8' }); console.log(content.length); } finally { await handle.close(); }
#Как проверить результат и что делать, если не помогло
Повторяемая партия файлов обрабатывается без EMFILE, а количество дескрипторов не растёт от запуска к запуску.
Если неисправность повторилась, выпишите первый код ошибки и действие, на котором она возвращается. Сравните версию Node.js/npm, рабочий каталог, настройки процесса и журнал тестового запуска. Откатите только внесённые изменения из предварительно сохранённой копии, затем разберите причину на отдельной среде.