fs.writeFileSync дает ошибку: UNKNOWN, правильный способ сделать синхронную запись файла в nodejs

У меня есть серверное приложение NodeJS. У меня есть эта строка кода для моего ведения журнала:

fs.writeFileSync(__dirname + "/../../logs/download.html.xml", doc.toString());

Иногда работает корректно, но при большой нагрузке выдает такое исключение:

Error: UNKNOWN, unknown error 'download.html.xml'

PS: я нашел здесь ссылку: http://www.daveeddy.com/2013/03/26/synchronous-file-io-in-nodejs/ Blogger описывает, что writeFileSync на самом деле не заканчивает запись по возвращении. Есть ли правильный способ сделать это синхронно, то есть без обратных вызовов?


person Stepan Yakovenko    schedule 27.09.2015    source источник
comment
Что вы считаете правильным?   -  person Soren    schedule 15.10.2015
comment
Кроме того, неясно, спрашиваете ли вы, что вызывает вашу ошибку, или как вы выполняете синхронизацию записи в файловую систему - вряд ли они связаны.   -  person Soren    schedule 15.10.2015
comment
Почему вы не хотите использовать обратные вызовы? Выполнение синхронной операции заблокирует цикл событий, и это будет особенно плохо, поскольку ваше приложение находится под большой нагрузкой.   -  person Rahat Mahbub    schedule 16.10.2015
comment
@RahatMahbub, для этого потребовался бы очень огромный рефакторинг, сейчас для этого нет ресурсов.   -  person Stepan Yakovenko    schedule 16.10.2015
comment
@stiv действительно ли потребуется такой большой рефакторинг? Вероятно, это стоило бы сделать в долгосрочной перспективе. Использование writeFileSync не использует возможности javascript и не позволяет изящно справиться с этой проблемой.   -  person jjbskir    schedule 17.10.2015
comment
вы открываете много файлов с помощью writeFileSync? Я имею в виду, это вы заканчиваете дескрипторы? В этом случае вы можете рассмотреть возможность реализации пула писателей с очередью для размещения ваших запросов на запись, даже если это имеет проблему, которая имеет тенденцию занимать больше памяти (поскольку вы паркуете там свои исходящие doc, которые ждут worker).   -  person skypjack    schedule 19.10.2015
comment
статья, на которую вы ссылаетесь, заканчивается If you want to open a file for synchronous IO, you'll have to use the lower level fs functions that Node offers such as fs.open() and fs.fsync()., разве этого недостаточно?   -  person dandavis    schedule 20.10.2015
comment
вы сказали, что это потребует очень серьезного рефакторинга, сейчас для этого нет ресурсов. вы можете когда-нибудь перезаписать writeFileSync, отбросив исходный и позволив ему работать асинхронно, а затем выполнить плавную миграцию во времени и откат этой функции после ее выполнения.   -  person skypjack    schedule 22.10.2015
comment
@skypjack, отличная идея!   -  person Stepan Yakovenko    schedule 20.11.2015
comment
@Степан Яковенко, вы хотите, чтобы я написал это в ответ? Если это решит и может помочь будущим поискам...   -  person skypjack    schedule 20.11.2015
comment
да, конечно, я могу принять это   -  person Stepan Yakovenko    schedule 20.11.2015


Ответы (2)


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

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

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

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

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

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

Конечно, это может быть подходящим решением для всплеска запросов, разделенных во времени, но, возможно, оно не подходит для фиксированных нагрузок, постоянных во времени.

person skypjack    schedule 19.11.2015

Когда вы выполняете writeFileSync, вы получаете файловый дескриптор файла. ОС ограничивает количество файловых дескрипторов, которые могут быть открыты в данный момент времени. Таким образом, при интенсивном использовании вы можете фактически достичь предела. Один из способов узнать, так ли это, — использовать ulimit и установить для него значение «неограниченно».

Другая возможность — ошибки ввода-вывода. Например, закрытие дескриптора файла не удастся, если произойдет ошибка ввода-вывода.

person rollingBalls    schedule 16.10.2015
comment
Из того, что я видел, достижение предела дескриптора приводит к конкретной ошибке (EMFILE), а не к неизвестной, так что, вероятно, причина здесь не в этом. - person Jakub Wasilewski; 21.10.2015