如何防止node.js崩溃? try-catch不起作用

时间:2011-05-14 02:04:29

标签: node.js crash try-catch production-environment

根据我的经验,php服务器会向日志或服务器端抛出异常,但node.js只是崩溃。用try-catch包围我的代码也不起作用,因为一切都是异步完成的。我想知道其他人在他们的生产服务器上做了什么。

9 个答案:

答案 0 :(得分:120)

其他答案真的很疯狂,因为您可以在http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception

处阅读Node自己的文档

如果有人使用其他声明的答案,请阅读节点文档:

  

请注意,uncaughtException是一种非常粗略的异常处理机制,可能会在将来删除

<强> PM2

首先,我强烈建议为PM2安装Node.js。 PM2非常适合处理崩溃和监控节点应用以及负载平衡。 PM2会在崩溃时立即启动Node应用程序,因任何原因停止或甚至在服务器重新启动时停止。因此,如果有一天甚至在管理我们的代码之后,应用程序崩溃,PM2可以立即重新启动它。有关详细信息,请Installing and Running PM2

现在回到我们的解决方案,以防止应用程序本身崩溃。

因此,经过我终于想出了Node文档本身的建议:

  

请勿使用uncaughtException,而应使用domains代替cluster。如果您使用uncaughtException,请在每次未处理的异常后重启您的应用程序!

使用群集

DOMAIN

我们实际做的是向触发错误的请求发送错误响应,同时让其他人在正常时间内完成,并停止侦听该工作人员中的新请求。

通过这种方式,域使用与群集模块密切相关,因为主进程可以在工作程序遇到错误时分叉新工作程序。请参阅以下代码以了解我的意思

通过使用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 with Cluster是节点文档建议的唯一好的解决方案。

深入了解DomainCluster阅读

https://nodejs.org/api/domain.html#domain_domainStability: 0 - Deprecated

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

感谢@Stanley Luo向我们分享了关于群集和域名的精彩深入解释

Cluster & Domains

答案 1 :(得分:73)

我把这段代码放在我的require语句和全局声明之下:

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

适合我。我唯一不喜欢的是,如果我让事情崩溃的话,我得到的信息就不多了。

答案 2 :(得分:27)

如上所述[{3}},您会发现error.stack提供了更完整的错误消息,例如导致错误的行号:

process.on('uncaughtException', function (error) {
   console.log(error.stack);
});

答案 3 :(得分:12)

尝试supervisor

npm install supervisor
supervisor app.js

或者您可以改为安装forever

所有这一切都是通过重启来恢复服务器崩溃。

可以在代码中使用

forever来优雅地恢复任何崩溃的进程。

forever文档以编程方式提供有关退出/错误处理的可靠信息。

答案 4 :(得分:7)

使用try-catch可以解决未捕获的错误,但在某些复杂的情况下,它不能正常工作,例如捕获异步函数。请记住,在Node中,任何异步函数调用都可能包含潜在的应用程序崩溃操作。

使用uncaughtException是一种解决方法,但它被认为是低效的,很可能会在未来的Node版本中删除,所以不要指望它。

理想的解决方案是使用域名:http://nodejs.org/api/domain.html

要确保您的应用已启动并运行,即使您的服务器崩溃,请使用以下步骤:

  1. 使用节点集群为每个核心分叉多个进程。因此,如果一个进程死亡,另一个进程将自动启动。退房:http://nodejs.org/api/cluster.html

  2. 使用域来捕获异步操作,而不是使用try-catch或uncaught。我不是说尝试捕捉或未捕获是不好的想法!

  3. 使用forever / supervisor监控您的服务

  4. 添加守护程序以运行您的节点应用程序:http://upstart.ubuntu.com

  5. 希望这有帮助!

答案 5 :(得分:4)

试试pm2节点模块它是非常一致的并且有很好的文档。具有内置负载均衡器的Node.js应用程序的生产流程管理器。请避免此问题的uncaughtException。 https://github.com/Unitech/pm2

答案 6 :(得分:0)

UncaughtException是“非常粗略的机制”(如此真实),现在不推荐使用域名。但是,我们仍然需要一些机制来捕获(逻辑)域周围的错误。图书馆:

https://github.com/vacuumlabs/yacol

可以帮助你做到这一点。通过一些额外的写作,您可以在代码周围拥有漂亮的域语义!

答案 7 :(得分:0)

善于改善:

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();
});

答案 8 :(得分:0)

默认情况下,Node.js 通过将堆栈跟踪打印到 stderr 并以代码 1 退出,覆盖任何先前设置的 process.exitCode 来处理此类异常。

know more

process.on('uncaughtException', (err, origin) => {
    console.log(err);
});