Сделать node.js не выходить с ошибкой

Я работаю над ориентированным на websocket node.js-сервером с помощью Socket.IO. Я заметил ошибку, когда некоторые браузеры не следуют правильной процедуре подключения к серверу, и код не написан, чтобы грамотно обрабатывать его, и, короче говоря, он вызывает метод для объекта, который никогда не был настроен, таким образом убивая сервер из-за ошибки.

Моя проблема связана не с ошибкой, а с тем фактом, что при возникновении таких ошибок весь сервер отключается. Есть ли что-нибудь, что я могу сделать на глобальном уровне в узле, чтобы сделать это, если произойдет ошибка, он просто зарегистрирует сообщение, возможно, убьет событие, но процесс сервера продолжит работу?

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

Вы можете присоединить слушателя к событию uncaughtException объекта процесса.

Код, взятый из фактической ссылки API Node.js (это второй элемент под «процессом»):

 process.on('uncaughtException', function (err) { console.log('Caught exception: ', err); }); setTimeout(function () { console.log('This will still run.'); }, 500); // Intentionally cause an exception, but don't catch it. nonexistentFunc(); console.log('This will not run.'); 

Все, что вам нужно сделать, это зарегистрировать его или сделать с ним что-либо, если вы знаете, при каких обстоятельствах ошибка возникает, вы должны подать сообщение об ошибке на странице Socket.IO GitHub:
https://github.com/LearnBoost/Socket.IO-node/issues

Использование uncaughtException – очень плохая идея.

Лучшей альтернативой является использование доменов в Node.js 0.8. Если вы используете более раннюю версию Node.js, используйте ее навсегда, чтобы перезапустить свои процессы или даже лучше использовать кластер узлов, чтобы вызвать несколько рабочих процессов и перезапустить рабочего на событие uncaughtException.

От: http://nodejs.org/api/process.html#process_event_uncaughtexception

Предупреждение: правильное использование «uncaughtException»

Обратите внимание, что «uncaughtException» является грубым механизмом обработки исключений, предназначенным для использования только в качестве последнего средства. Событие не должно использоваться в качестве эквивалента On Error Resume Next. Необработанные исключения по сути означают, что приложение находится в неопределенном состоянии. Попытка возобновления кода приложения без должного восстановления из исключения может вызвать дополнительные непредвиденные и непредсказуемые проблемы.

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

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

Правильное использование «uncaughtException» – это выполнить синхронную очистку выделенных ресурсов (например, дескрипторы файлов, дескрипторы и т. Д.) Перед закрытием процесса. Небезопасно возобновлять нормальную работу после «uncaughtException».

Чтобы перезапустить аварийное приложение более надежным способом, независимо от того, выбрано ли исключение uncaughtException или нет, внешний монитор должен использоваться в отдельном процессе для обнаружения сбоев приложений и восстановления или перезапуска при необходимости.

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

Некоторые фреймворки, такие как express , позволят вам поймать определенные типы ошибок (когда метод async возвращает объект ошибки), но есть и другие условия, которые вы не можете поймать с помощью глобального обработчика ошибок. Это ограничение (на мой взгляд) Узел и, возможно, присуще асинхронному программированию в целом.

Например, скажем, у вас есть следующий express-обработчик:

 app.get("/test", function(req, res, next) { require("fs").readFile("/some/file", function(err, data) { if(err) next(err); else res.send("yay"); }); }); 

Предположим, что файл «some / file» на самом деле не существует. В этом случае fs.readFile вернет ошибку в качестве первого аргумента методу обратного вызова. Если вы проверите это и сделаете следующее (ошибочно), когда это произойдет, обработчик ошибок по умолчанию будет захвачен и сделает все, что вы сделаете (например, верните 500 для пользователя). Это изящный способ справиться с ошибкой. Конечно, если вы забудете позвонить next(err) , это не сработает.

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

 app.get("/test", function(req, res, next) { require("fs").readFile("/some/file", function(err, data) { if(err) next(err); else { nullObject.someMethod(); //throws a null reference exception res.send("yay"); } }); }); 

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

В настоящее время в узле нет функций глобального обработчика ошибок для обработки этого случая. Вы не можете поставить гигантскую try/catch все ваши express-обработчики, потому что к моменту выполнения вашего обратного вызова asyn эти блоки try/catch больше не находятся в области видимости. Это просто характер асинхронного кода, он разбивает парадигму обработки ошибок try / catch.

AFAIK, ваш единственный ресурс здесь – поставить блоки try/catch вокруг синхронных частей вашего кода внутри каждого из ваших асинхронных обратных вызовов, примерно так:

 app.get("/test", function(req, res, next) { require("fs").readFile("/some/file", function(err, data) { if(err) { next(err); } else { try { nullObject.someMethod(); //throws a null reference exception res.send("yay"); } catch(e) { res.send(500); } } }); }); 

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

Некоторые люди думают, что то, что делает Node в этих случаях (то есть, умереть), – это правильная вещь, потому что ваша система находится в противоречивом состоянии, и у вас нет другого выбора. Я не согласен с этими рассуждениями, но я не буду вдаваться в философские дебаты об этом. Дело в том, что с помощью Node ваши варианты – это много маленьких блоков try/catch или надеемся, что ваше тестовое покрытие будет достаточно хорошим, чтобы этого не произошло. Вы можете поместить что-то вроде выскочки или супервизора, чтобы перезапустить приложение, когда оно опускается, но это просто устранение проблемы, а не решение.

Node.js имеет в настоящее время нестабильную функцию, называемую доменами, которая, как представляется, устраняет эту проблему, хотя я мало знаю об этом.

Я только что собрал class, который слушает необработанные исключения, и когда он видит одно:

  • выводит трассировку стека на консоль
  • записывает его в свой собственный файл журнала
  • отправляет вам трассировку стека
  • перезапускает сервер (или убивает его, зависит от вас)

Это потребует небольшой настройки для вашего приложения, поскольку я пока не сделал его общим, но это всего лишь несколько строк, и это может быть то, что вы ищете!

Проверьте это!

Примечание: на данный момент это более 4 лет, незавершенное, и теперь может быть лучший способ – я не знаю!)

 process.on ( 'uncaughtException', function (err) { var stack = err.stack; var timeout = 1; // print note to logger logger.log("SERVER CRASHED!"); // logger.printLastLogs(); logger.log(err, stack); // save log to timestamped logfile // var filename = "crash_" + _2.formatDate(new Date()) + ".log"; // logger.log("LOGGING ERROR TO "+filename); // var fs = require('fs'); // fs.writeFile('logs/'+filename, log); // email log to developer if(helper.Config.get('email_on_error') == 'true') { logger.log("EMAILING ERROR"); require('./Mailer'); // this is a simple wrapper around nodemailer http://documentup.com/andris9/nodemailer/ helper.Mailer.sendMail("GAMEHUB NODE SERVER CRASHED", stack); timeout = 10; } // Send signal to clients // logger.log("EMITTING SERVER DOWN CODE"); // helper.IO.emit(SIGNALS.SERVER.DOWN, "The server has crashed unexpectedly. Restarting in 10s.."); // If we exit straight away, the write log and send email operations wont have time to run setTimeout ( function() { logger.log("KILLING PROCESS"); process.exit(); }, // timeout * 1000 timeout * 100000 // extra time. pm2 auto-restarts on crash... ); } ); 

Была аналогичная проблема. Ответ Иво хорош. Но как вы можете поймать ошибку в цикле и продолжить?

 var folder='/anyFolder'; fs.readdir(folder, function(err,files){ for(var i=0; i 

Здесь fs.statSynch выдает ошибку (против скрытого файла в Windows, который barfs я не знаю почему). Ошибка может быть поймана методом process.on (...), но цикл останавливается.

Я попытался добавить обработчик напрямую:

 var stats = fs.statSync(folder+'/'+files[i]).on('error',function(err){console.log(err);}); 

Это тоже не сработало.

Добавление try / catch вокруг сомнительного fs.statSynch () было лучшим решением для меня:

 var stats; try{ stats = fs.statSync(path); }catch(err){console.log(err);} 

Затем это привело к исправлению кода (создание чистого пути var из папки и файла).

Я нашел PM2 лучшим решением для обработки серверов узлов, одного и нескольких экземпляров

Один из способов сделать это – открутить дочерний процесс и связаться с родительским процессом через событие «сообщение».

В дочернем процессе, где происходит ошибка, поймите это с помощью «uncaughtException», чтобы избежать сбоя приложения. Имейте в виду, что Исключения, выброшенные из обработчика события , не будут пойманы . Как только ошибка будет обнаружена безопасно, отправьте сообщение, например: {finish: false} .

Родительский процесс прослушивает событие сообщения и снова отправляет сообщение дочернему процессу для повторного запуска функции.

Детский процесс:

 // In child.js // function causing an exception const errorComputation = function() { for (let i = 0; i < 50; i ++) { console.log('i is.......', i); if (i === 25) { throw new Error('i = 25'); } } process.send({finish: true}); } // Instead the process will exit with a non-zero exit code and the stack trace will be printed. This is to avoid infinite recursion. process.on('uncaughtException', err => { console.log('uncaught exception..',err.message); process.send({finish: false}); }); // listen to the parent process and run the errorComputation again process.on('message', () => { console.log('starting process ...'); errorComputation(); }) 

Родительский процесс:

 // In parent.js const { fork } = require('child_process'); const compute = fork('child.js'); // listen onto the child process compute.on('message', (data) => { if (!data.finish) { compute.send('start'); } else { console.log('Child process finish successfully!') } }); // send initial message to start the child process. compute.send('start'); 
  • Почему gulp.src не нравится передавать массив полных путей к файлам?
  • Как определить IP-адрес пользователя в узле
  • Проблемы с запуском Npm в приложении phonecat от AngularJS
  • Почему мангуста всегда добавляет s в конец имени моей коллекции
  • ограничение памяти в Node.js (и хром V8)
  • Веб-сайты Windows Azure переопределяют мои страницы ошибок 404 и 500 в моем приложении node.js
  • Как получить доступ к параметрам GET после «?» В Express?
  • Разрешить запрос CORS REST в приложение Express / Node.js на Heroku
  • Как узнать, зарегистрирован ли пользователь в файле passport.js?
  • Ошибка грубой вахты - Ожидание ... Неустранимая ошибка: смотрите ENOSPC
  • Что такое «подписанные» куки в connect / expressjs?
  • Давайте будем гением компьютера.