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

发布于 2024-11-07 12:08:18 字数 108 浏览 0 评论 0原文

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

From my experience, a php server would throw an exception to the log or to the server end, but node.js just simply crashes. Surrounding my code with a try-catch doesn't work either since everything is done asynchronously. I would like to know what does everyone else do in their production servers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

风筝在阴天搁浅。 2024-11-14 12:08:18

PM2

首先,我强烈建议为 Node.js 安装 PM2。 PM2 非常擅长处理崩溃、监控 Node 应用程序以及负载平衡。每当 PM2 崩溃、因任何原因停止甚至服务器重新启动时,PM2 都会立即启动 Node 应用程序。因此,如果有一天,即使在管理我们的代码之后,应用程序崩溃了,PM2 也可以立即重新启动它。有关更多信息,安装和运行 PM2

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

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

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

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

因此,在浏览完之后,我终于得出了 Node 文档本身的建议:

不要使用uncaughtException,而是使用domainscluster。如果您确实使用uncaughtException,请在每次未处理的异常后重新启动您的应用程序!

DOMAINCluster

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

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

通过使用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 完成,该模块将被完全弃用。绝对必须拥有域提供的功能的用户可能暂时依赖它,但应该预计将来必须迁移到不同的解决方案。

但在没有引入新的替代方案之前,带有集群的域是节点文档建议的唯一好的解决方案。

要深入了解 DomainCluster,请阅读

https://nodejs.org/api/domain.html#domain_domain稳定性:0 - 已弃用

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

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

集群和集群域名

PM2

First of all, I would highly recommend installing PM2 for Node.js. PM2 is really great at handling crash and monitoring Node apps as well as load balancing. PM2 immediately starts the Node app whenever it crashes, stops for any reason or even when server restarts. So, if someday even after managing our code, app crashes, PM2 can restart it immediately. For more info, Installing and Running PM2

Other answers are really insane as you can read at Node's own documents at http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception

If someone is using other stated answers read Node Docs:

Note that uncaughtException is a very crude mechanism for exception handling and may be removed in the future

Now coming back to our solution to preventing the app itself from crashing.

So after going through I finally came up with what Node document itself suggests:

Don't use uncaughtException, use domains with cluster instead. If you do use uncaughtException, restart your application after every unhandled exception!

DOMAIN with Cluster

What we actually do is send an error response to the request that triggered the error, while letting the others finish in their normal time, and stop listening for new requests in that worker.

In this way, domain usage goes hand-in-hand with the cluster module, since the master process can fork a new worker when a worker encounters an error. See the code below to understand what I mean

By using Domain, and the resilience of separating our program into multiple worker processes using Cluster, we can react more appropriately, and handle errors with much greater safety.

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

Though Domain is pending deprecation and will be removed as the new replacement comes as stated in Node's Documentation

This module is pending deprecation. Once a replacement API has been finalized, this module will be fully deprecated. Users who absolutely must have the functionality that domains provide may rely on it for the time being but should expect to have to migrate to a different solution in the future.

But until the new replacement is not introduced, Domain with Cluster is the only good solution what Node Documentation suggests.

For in-depth understanding Domain and Cluster read

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

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

Thanks to @Stanley Luo for sharing us this wonderful in-depth explanation on Cluster and Domains

Cluster & Domains

烂柯人 2024-11-14 12:08:18

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

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

对我有用。我唯一不喜欢它的是,如果我让它崩溃的话,我不会得到尽可能多的信息。

I put this code right under my require statements and global declarations:

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

works for me. the only thing i don't like about it is I don't get as much info as I would if I just let the thing crash.

梦幻的心爱 2024-11-14 12:08:18

正如此处所述,您'会发现error.stack提供了更完整的错误消息,例如导致错误的行号:

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

As mentioned here you'll find error.stack provides a more complete error message such as the line number that caused the error:

process.on('uncaughtException', function (error) {
   console.log(error.stack);
});
岁月静好 2024-11-14 12:08:18

尝试 supervisor

npm install supervisor
supervisor app.js

或者你可以安装 永远 代替。

所有这一切都会在服务器崩溃时通过重新启动来恢复它。

可以在代码中使用 forever 来正常恢复任何崩溃的进程。

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

Try supervisor

npm install supervisor
supervisor app.js

Or you can install forever instead.

All this will do is recover your server when it crashes by restarting it.

forever can be used within the code to gracefully recover any processes that crash.

The forever docs have solid information on exit/error handling programmatically.

浮华 2024-11-14 12:08:18

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

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

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

即使服务器崩溃,也要确保您的应用程序正常运行,请使用以下步骤:

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

  2. 使用域捕获异步操作而不是使用 try-catch 或 uncaught。我并不是说 try-catch 或 uncaught 是个坏主意!

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

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

希望这有帮助!

Using try-catch may solve the uncaught errors, but in some complex situations, it won't do the job right such as catching async function. Remember that in Node, any async function calls can contain a potential app crashing operation.

Using uncaughtException is a workaround but it is recognized as inefficient and is likely to be removed in the future versions of Node, so don't count on it.

Ideal solution is to use domain: http://nodejs.org/api/domain.html

To make sure your app is up and running even your server crashed, use the following steps:

  1. use node cluster to fork multiple process per core. So if one process died, another process will be auto boot up. Check out: http://nodejs.org/api/cluster.html

  2. use domain to catch async operation instead of using try-catch or uncaught. I'm not saying that try-catch or uncaught is bad thought!

  3. use forever/supervisor to monitor your services

  4. add daemon to run your node app: http://upstart.ubuntu.com

hope this helps!

单身狗的梦 2024-11-14 12:08:18

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

Give a try to pm2 node module it is far consistent and has great documentation. Production process manager for Node.js apps with a built-in load balancer. please avoid uncaughtException for this problem.
https://github.com/Unitech/pm2

薆情海 2024-11-14 12:08:18

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

Works great on 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();
});
鯉魚旗 2024-11-14 12:08:18

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

了解更多

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

By default, Node.js handles such exceptions by printing the stack trace to stderr and exiting with code 1, overriding any previously set process.exitCode.

know more

process.on('uncaughtException', (err, origin) => {
    console.log(err);
});
无远思近则忧 2024-11-14 12:08:18

UncaughtException 是“一种非常粗糙的机制”(确实如此),并且域现在已被弃用。然而,我们仍然需要某种机制来捕获(逻辑)域周围的错误。库:

https://github.com/vacuumlabs/yacol

可以帮助您做到这一点。通过一些额外的编写,您可以在代码中拥有良好的域语义!

UncaughtException is "a very crude mechanism" (so true) and domains are deprecated now. However, we still need some mechanism to catch errors around (logical) domains. The library:

https://github.com/vacuumlabs/yacol

can help you do this. With a little of extra writing you can have nice domain semantics all around your code!

∞梦里开花 2024-11-14 12:08:18

为了避免 NodeJS 服务器因 unhandledRejectionuncaughtException 崩溃,请将以下代码片段放入您的入口文件 ma​​in.ts

process.on('unhandledRejection', (reason: string, p: Promise<any>) => {
  // I just caught an unhandled promise rejection,
  // since we already have fallback handler for unhandled errors (see below),
  // let throw and let him handle that
  throw reason;
});

process.on('uncaughtException', (error: Error) => {
  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed
  errorManagement.handler.handleError(error);
  if (!errorManagement.handler.isTrustedError(error))
    process.exit(1);
});

To avoid nodejs server crashing because of unhandledRejection or uncaughtException, let put the below snippet into your entry file main.ts

process.on('unhandledRejection', (reason: string, p: Promise<any>) => {
  // I just caught an unhandled promise rejection,
  // since we already have fallback handler for unhandled errors (see below),
  // let throw and let him handle that
  throw reason;
});

process.on('uncaughtException', (error: Error) => {
  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed
  errorManagement.handler.handleError(error);
  if (!errorManagement.handler.isTrustedError(error))
    process.exit(1);
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文