Как предотвратить сбой node.js? пробная ловля не работает

157

По моему опыту, php-сервер генерирует исключение в журнал или на конец сервера, но node.js просто вылетает. Окружение моего кода try-catch также не работает, так как все выполняется асинхронно. Я хотел бы знать, что все остальные делают на своих производственных серверах.

TiansHUo
источник

Ответы:

132

Другие ответы действительно безумны, так как вы можете прочитать их в собственных документах по адресу http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception

Если кто-то использует другие заявленные ответы, прочитайте Node Docs:

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

PM2

Прежде всего, я очень рекомендую установить PM2для Node.js. PM2 действительно отлично справляется с обработкой сбоев и мониторингом приложений Node, а также с балансировкой нагрузки. PM2 немедленно запускает приложение Node в случае его сбоя, остановки по любой причине или даже после перезапуска сервера. Так что, если когда-нибудь, даже после управления нашим кодом, произойдет сбой приложения, PM2 может перезапустить его немедленно. Для получения дополнительной информации, Установка и запуск PM2

Теперь вернемся к нашему решению по предотвращению сбоя самого приложения.

Так что после прохождения я наконец-то пришел к выводу, что сам документ Node предлагает:

Не следует использовать uncaughtException, использовать domainsс clusterвместо этого. Если вы используете uncaughtException, перезапустите приложение после каждого необработанного исключения!

ДОМЕН с кластером

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

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

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

var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;

if(cluster.isMaster) 
{
   cluster.fork();
   cluster.fork();

   cluster.on('disconnect', function(worker) 
   {
       console.error('disconnect!');
       cluster.fork();
   });
} 
else 
{
    var domain = require('domain');
    var server = require('http').createServer(function(req, res) 
    {
        var d = domain.create();
        d.on('error', function(er) 
        {
            //something unexpected occurred
            console.error('error', er.stack);
            try 
            {
               //make sure we close down within 30 seconds
               var killtimer = setTimeout(function() 
               {
                   process.exit(1);
               }, 30000);
               // But don't keep the process open just for that!
               killtimer.unref();
               //stop taking new requests.
               server.close();
               //Let the master know we're dead.  This will trigger a
               //'disconnect' in the cluster master, and then it will fork
               //a new worker.
               cluster.worker.disconnect();

               //send an error to the request that triggered the problem
               res.statusCode = 500;
               res.setHeader('content-type', 'text/plain');
               res.end('Oops, there was a problem!\n');
           } 
           catch (er2) 
           {
              //oh well, not much we can do at this point.
              console.error('Error sending 500!', er2.stack);
           }
       });
    //Because req and res were created before this domain existed,
    //we need to explicitly add them.
    d.add(req);
    d.add(res);
    //Now run the handler function in the domain.
    d.run(function() 
    {
        //You'd put your fancy application logic here.
        handleRequest(req, res);
    });
  });
  server.listen(PORT);
} 

Несмотря на то, Domainчто ожидается устаревшая версия, она будет удалена, так как новая замена выполняется в соответствии с документацией Node.

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

Но пока новая замена не будет введена, Домен с Кластером - единственное хорошее решение, которое предлагает Документация узла.

Для глубокого понимания Domainи Clusterчтения

https://nodejs.org/api/domain.html#domain_domain (Stability: 0 - Deprecated)

https://nodejs.org/api/cluster.html

Спасибо @Stanley Luo за то, что поделились этим замечательным подробным объяснением о кластере и доменах.

Кластер и Домены

воздушный
источник
9
Предупреждение: домен ожидает устаревания: ссылка . Предложенный метод из документов Node заключается в использовании cluster: link .
Пол
4
restart your application after every unhandled exception!Если 2000 пользователей используют веб-сервер узла для потоковой передачи видео, а 1 пользователь получил исключение, то перезапуск не будет прерывать всех остальных пользователей?
Викас Бансал
2
@VikasBansal Да , что, безусловно , прерывание все пользователи , и поэтому это плохо использовать uncaughtExceptionи использовать Domainс Clusterвместо так, если один пользователь сталкивается исключение , чтобы только его поток удаляется из кластера и создал новый для него. И вам не нужно перезагружать сервер Node. Находясь на другой стороне, если вы используете, uncaughtExceptionвы должны перезапускать сервер каждый раз, когда любой из ваших пользователей сталкивается с проблемой. Итак, используйте домен с кластером.
Эйри
3
что мы должны делать, когда domainполностью устарели и удалены?
Джас
3
Нашел этот учебник для тех, кто не понимает концепцию clusterи workers: sitepoint.com/…
Стэнли Ло
81

Я поместил этот код прямо под мои требования и глобальные объявления:

process.on('uncaughtException', function (err) {
  console.error(err);
  console.log("Node NOT Exiting...");
});

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

hvgotcodes
источник
45
Предупреждение: этот метод работает хорошо, НО помните, что ВСЕ HTTP-ответы должны быть правильно завершены. Это означает, что если во время обработки HTTP-запроса возникает неперехваченное исключение, вы все равно должны вызвать end () для объекта http.ServerResponse. Однако вы реализуете это зависит от вас. Если вы этого не сделаете, запрос будет зависать, пока браузер не сдастся. Если у вас достаточно этих запросов, серверу может не хватить памяти.
BMiner
3
@BMiner, не могли бы вы предоставить лучшую реализацию? Я заметил эту проблему (зависание запроса), так что это на самом деле не лучше, чем просто перезапустить сервер foreverили что-то в этом роде.
pixelfreak
6
Это требует подробного объяснения. Я знаю, что это отстой, но всякий раз, когда возникает необработанное исключение, ваш сервер должен перезагрузиться как можно скорее. Действительно, цель события uncaughtException - использовать его как возможность отправить электронное письмо с предупреждением, а затем использовать process.exit (1); выключить сервер. Вы можете использовать навсегда или что-то подобное, чтобы перезапустить сервер. Любые ожидающие HTTP-запросы прекратят работу и завершатся сбоем. Ваши пользователи будут злиться на вас. Но это лучшее решение. Почему ты спрашиваешь? Оформить заказ stackoverflow.com/questions/8114977/…
BMiner
3
Чтобы получить больше информации о неперехваченной ошибке, используйте: console.trace (err.stack);
Джесси Данлэп
2
ВНИМАНИЕ: документация для узла безоговорочно
Джереми Логан
28

Как упомянуто здесь, вы найдете error.stackболее полное сообщение об ошибке, например номер строки, вызвавшей ошибку:

process.on('uncaughtException', function (error) {
   console.log(error.stack);
});
Шон Баннистер
источник
12

Пытаться supervisor

npm install supervisor
supervisor app.js

Или вы можете установить foreverвместо.

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

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

В foreverдокументы имеют надежную информацию о выходе / обработки ошибок программно.

Raynos
источник
9
Конечно, это не может быть решением ... Во время, когда сервер не работает, он не может отвечать на новые входящие запросы. Из кода приложения может возникнуть исключение - сервер должен ответить ошибкой 500, а не просто аварийно завершить работу и надеяться, что он перезапустится.
Муравей Кучера
20
Таким образом, как хакер, можно выяснить, что им нужно отправить простой запрос на сервер и пропустить параметр запроса - что приводит к неопределенности в javascript, что приводит к сбою node.js. С твоим предложением я могу несколько раз убить весь твой кластер. Ответ заключается в том, чтобы заставить приложение корректно завершиться с ошибкой - то есть обработать необработанное исключение, а не сбой. что если сервер обрабатывает много сеансов VoIP? для него неприемлемо, что он рухнет и сгорит, а все существующие сеансы умрут с ним. Ваши пользователи скоро уйдут.
Муравей Кучера
5
@AntKutschera, поэтому исключения должны быть исключительными. Исключения должны стрелять только в тех ситуациях , когда вы не можете восстановить и где процесс должен врезаться. Вы должны использовать другие средства для обработки этих исключительных случаев. Но я вижу вашу точку зрения. Вы должны терпеть неудачу изящно, где это возможно. Однако есть случаи, когда продолжение с поврежденным состоянием принесет больше ущерба.
Рэйнос
2
Да, здесь есть разные школы мысли. Как я узнал (Java, а не Javascript), есть приемлемые ожидания, которые вы должны ожидать, известные как бизнес-исключения, а также есть исключения или ошибки времени выполнения, которые вы не должны ожидать восстановления, например, нехватка памяти. Одна проблема из-за того, что не происходит сбоев, заключается в том, что некоторая библиотека, которую я пишу, может объявить, что она выдает исключение в случае чего-то восстанавливаемого, скажем, где пользователь может исправить свой ввод. в своем приложении вы не читаете мои документы и просто аварийно завершаете работу, где пользователь, возможно, смог восстановить данные
Ant Kutschera
1
@AntKutschera Вот почему мы регистрируем исключения. Вы должны проанализировать свои производственные журналы на наличие распространенных исключений и выяснить, можно ли и как можно восстановить их, вместо того, чтобы дать сбой серверу. Я использовал эту методологию с PHP, Ruby on Rails и Node. Независимо от того, выйдете ли вы из процесса или нет, каждый раз, когда вы выдаете ошибку 500, вы оказываете своим пользователям медвежью услугу. Это не JavaScript или специфичная для Node практика.
Эрик Эллиотт
7

Использование try-catch может решить необработанные ошибки, но в некоторых сложных ситуациях он не будет работать правильно, например, перехват асинхронной функции. Помните, что в Node любые вызовы асинхронных функций могут содержать потенциальную операцию сбоя приложения.

Использование uncaughtException- это обходной путь, но оно признано неэффективным и, вероятно, будет удалено в будущих версиях Node, поэтому не рассчитывайте на это.

Идеальным решением является использование домена: http://nodejs.org/api/domain.html

Чтобы убедиться, что ваше приложение запущено и работает даже при сбое сервера, выполните следующие действия:

  1. используйте кластер узлов для раскрутки нескольких процессов на ядро. Таким образом, если один процесс умер, другой процесс будет автоматически загружаться. Проверьте: http://nodejs.org/api/cluster.html

  2. используйте домен для перехвата асинхронной операции вместо использования try-catch или uncaught. Я не говорю, что попытка поймать или не поймать - плохая мысль!

  3. использовать навсегда / супервизор для мониторинга ваших услуг

  4. добавьте демон для запуска приложения вашего узла: http://upstart.ubuntu.com

надеюсь это поможет!

Нам Нгуен
источник
4

Попробуйте модуль узла pm2, он достаточно последовательный и имеет отличную документацию. Менеджер производственного процесса для приложений Node.js со встроенным балансировщиком нагрузки. пожалуйста, избегайте uncaughtException для этой проблемы. https://github.com/Unitech/pm2

Вирандра Раторе
источник
`перезапускать ваше приложение после каждого необработанного исключения!` Если 2000 пользователей используют веб-сервер узла для потоковой передачи видео, а 1 пользователь получил исключение, то перезапуск не будет прерывать всех остальных пользователей?
Викас Бансал
Я был так счастлив, когда обнаружил PM2. отличная программа
Младен Янетович
0

UncaughtException - это «очень грубый механизм» (так верно), и домены сейчас устарели. Однако нам все еще нужен какой-то механизм для выявления ошибок вокруг (логических) доменов. Библиотека:

https://github.com/vacuumlabs/yacol

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

Томаш Кулич
источник
0

Отлично работает на restify:

server.on('uncaughtException', function (req, res, route, err) {
  log.info('******* Begin Error *******\n%s\n*******\n%s\n******* End Error *******', route, err.stack);
  if (!res.headersSent) {
    return res.send(500, {ok: false});
  }
  res.write('\n');
  res.end();
});
PH Андраде
источник