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

Tia*_*HUo 147 crash try-catch production-environment node.js

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

Abd*_*rai 126

其他答案真的很疯狂,因为您可以在http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception上阅读Node自己的文档.

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

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

PM2

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

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

所以经过我终于想出了Node文档本身的建议:

不要使用uncaughtException,使用domainscluster代替.如果您使用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);
} 
Run Code Online (Sandbox Code Playgroud)

虽然Domain正在等待弃用,但随着新的替代品的出现,将按照Node的文档中的说明进行删除

此模块正在等待弃用.更新API完成后,将完全弃用此模块.绝对必须具有域提供的功能的用户可能暂时依赖它,但是应该期望将来必须迁移到不同的解决方案.

但是,在没有引入新的替换之前,Domain with Cluster是Node Documentation建议的唯一好的解决方案.

深入了解DomainCluster阅读

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

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

感谢@Stanley Luo向我们分享了关于Cluster和Domains的这篇精彩深入的解释

群集和域

  • 一句警告,Domain正在等待弃用:[link](https://nodejs.org/api/domain.html).Node文档中建议的方法是使用cluster:[link](https://nodejs.org/api/cluster.html). (9认同)
  • `在每个未处理的异常后重新启动你的应用程序!`如果2000用户使用节点web服务器进行流视频,1个用户有异常,那么重启不会打断所有其他用户? (4认同)
  • 当`domain`被完全弃用并删除时我们该怎么办? (3认同)
  • 为那些不了解`cluster`和`workers`概念的人找到了这个教程:https://www.sitepoint.com/how-to-create-a-node-js-cluster-for-speeding-up - 您的应用程式/ (3认同)
  • @VikasBansal是的肯定会打断所有用户,这就是为什么使用`uncaughtException`并使用`Domain`而不是`Cluster`这样做的原因,如果一个用户面临异常,那么只有他的线程从集群中移除并创建一个新的为了他.而且您也不需要重新启动Node服务器.另一方面,如果您使用`uncaughtException`,则每次遇到任何用户问题时都必须重新启动服务器.因此,使用Domain with Cluster. (2认同)

hvg*_*des 75

我将此代码放在我的require语句和全局声明下:

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

适合我.我唯一不喜欢的是我没有得到尽可能多的信息,如果我让事情崩溃.

  • 需要注意的是:此方法运行良好,但请记住,所有HTTP响应都需要正确结束.这意味着如果在处理HTTP请求时发生未捕获的异常,则仍必须在http.ServerResponse对象上调用end().但是你实现这个取决于你.如果您不这样做,请求将挂起,直到浏览器放弃.如果您有足够的这些请求,服务器可能会耗尽内存. (44认同)
  • 这需要深入解释.我知道这很糟糕,但每当发生未捕获的异常时,您的服务器需要尽快重启.实际上,'uncaughtException'事件的目的是将它用作发送警告电子邮件的机会,然后使用process.exit(1); 关闭服务器.您可以永久使用或类似的东西来重新启动服务器.任何挂起的HTTP请求都将超时并失败.你的用户会生你的气.但是,这是最好的解决方案.你为什么问?结帐http://stackoverflow.com/questions/8114977/recover-from-uncaught-exception-in-node-js (6认同)
  • @BMiner,你能提供更好的实施吗?我注意到了这个问题(请求挂起)所以这真的不比仅使用`forever`或者其他东西重新启动服务器更好. (3认同)
  • 要从未捕获的错误中获取更多信息,请使用:console.trace(err.stack); (3认同)
  • 警告:节点的文档毫不含糊地说,你不应该这样做,因为它是疯狂的危险:http://nodejs.org/api/process.html#process_event_uncaughtexception (2认同)
  • 从node.js 0.10.35开始,这种技术不再有效.让我检查域解决方案是否有效. (2认同)

Sea*_*ter 27

如上所述,您将找到error.stack更完整的错误消息,例如导致错误的行号:

process.on('uncaughtException', function (error) {
   console.log(error.stack);
});
Run Code Online (Sandbox Code Playgroud)


Ray*_*nos 12

尝试 supervisor

npm install supervisor
supervisor app.js
Run Code Online (Sandbox Code Playgroud)

或者你可以安装forever.

所有这一切都是通过重新启动服务器崩溃时恢复服务器.

forever 可以在代码中使用,以优雅地恢复崩溃的任何进程.

forever文件对出口/错误处理程序可靠的信息.

  • 所以作为黑客,人们可以发现他们需要向服务器发送一个简单的请求并错过一个请求参数 - 这会导致javascript中的undef导致node.js崩溃.根据您的建议,我可以反复杀死您的整个群集.答案是使应用程序正常失败 - 即处理未捕获的异常而不是崩溃.如果服务器正在处理许多voip会话怎么办?它不容易崩溃和燃烧,并且所有那些现有的会话都会随之死亡.你的用户很快就会离开. (19认同)
  • 当然这不是解决方案......在服务器关闭的时间内,它无法响应新的传入请求.应用程序代码可能会抛出异常 - 服务器需要响应500错误,而不仅仅是崩溃并希望重新启动. (8认同)
  • @AntKutschera这就是为什么异常应该是例外的情况.只有当您_cannot_ recover以及进程_has_崩溃的情况下,才会触发异常.您应该使用其他方法来处理这些_exceptional_个案.但我明白你的观点.你应该尽可能优雅地失败.但是,如果继续处于腐败状态会造成更多伤害. (5认同)
  • 是的,这里有不同的思想流派.我学习它的方式(Java而不是Javascript)有可接受的预期,你应该期望,可能是业务异常,然后有运行时异常或错误,你不应该期望恢复,如内存不足.没有失败的一个问题是,我写的某个库可能会声明它会在可恢复的情况下抛出异常,例如用户可以更正其输入的位置.在你的应用程序中,你不读我的文档,只是崩溃,用户可能已经能够恢复 (2认同)

Nam*_*yen 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

希望这可以帮助!