根据我的经验,在 PHP 服务器中,异常会被记录到日志或者返回给服务器端,但是在 Node.js 中程序会直接崩溃。即使将代码放在 try-catch 中也不起作用,因为所有操作都是异步进行的。我想知道其他人在生产服务器上是如何处理这个问题的。
根据我的经验,在 PHP 服务器中,异常会被记录到日志或者返回给服务器端,但是在 Node.js 中程序会直接崩溃。即使将代码放在 try-catch 中也不起作用,因为所有操作都是异步进行的。我想知道其他人在生产服务器上是如何处理这个问题的。
PM2
首先,我强烈建议安装 PM2
用于 Node.js
。PM2 在处理崩溃和监控 Node 应用程序以及负载平衡方面非常出色。 PM2 可以在 Node 应用程序崩溃、因任何原因停止或甚至服务器重新启动时立即启动该应用程序。因此,即使在管理我们的代码后,应用程序崩溃,PM2 也可以立即重新启动它。有关更多信息,请参见安装和运行 PM2
其他答案真的很疯狂,您可以在 Node 的文档中阅读到:http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception
如果有人使用其他陈述的答案,请阅读 Node 文档:
请注意,
uncaughtException
是一种非常粗糙的异常处理机制,可能会在将来被删除
现在回到我们防止应用程序本身崩溃的解决方案。
因此,在经过研究后,我最终想到了 Node 文档本身建议的方法:
不要使用
uncaughtException
,而是使用带有cluster
的domains
。如果您确实使用uncaughtException
,请在每次未处理的异常后重新启动应用程序!
DOMAIN 和 Cluster
我们实际上是将错误响应发送到触发错误的请求,同时让其他请求按照正常时间完成,并停止在该工作进程中监听新请求。
这样,域使用与集群模块相辅相成,因为主进程可以在工作进程遇到错误时派生新的工作进程。请参见下面的代码,以了解我的意思
通过使用 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
将被废弃并替换为新的 API,但目前仍可使用。
该模块即将废弃。一旦有了替代 API,该模块将被完全弃用。当前确实需要 Domain 功能的用户可能暂时仍需依赖它,但未来应该准备迁移到其他解决方案。
在新的替代品推出之前,根据 Node 文档,结合 Cluster 使用 Domain 是唯一好的解决方案。
如需深入了解 Domain
和 Cluster
,请查看以下链接
https://nodejs.org/api/domain.html#domain_domain (稳定性: 0 - 废弃
)
https://nodejs.org/api/cluster.html
感谢 @Stanley Luo 分享的关于 Cluster 和 Domains 的深入解释。
我把这段代码放在我的require语句和全局声明下面:
process.on('uncaughtException', function (err) {
console.error(err);
console.log("Node NOT Exiting...");
});
对我来说有效。唯一不喜欢的是,与其让东西崩溃,我得到的信息不够多。
forever
或其他方法重新启动服务器要好。 - pixelfreak正如这里所提到的,你可以使用error.stack
来获取更完整的错误信息,例如导致错误的行号:
process.on('uncaughtException', function (error) {
console.log(error.stack);
});
试试supervisor
吧。
npm install supervisor
supervisor app.js
或者您可以安装forever
代替。
这只是在服务器崩溃时通过重启来恢复它。
forever
可以在代码中使用,以优雅地恢复任何崩溃的进程。
forever
文档提供了有关程序化退出/错误处理的可靠信息。
uncaughtException
是一种解决方法,但被认为是低效的,并且有可能在未来版本的 Node 中被删除,因此不能依赖它。尝试使用pm2 node模块,它更为稳定且文档详尽。这是一个用于Node.js应用程序的生产过程管理器,并内置了负载均衡器。请避免未捕获的异常问题。 https://github.com/Unitech/pm2
在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();
});
默认情况下,Node.js通过将堆栈跟踪打印到stderr并使用代码1退出来处理此类异常,覆盖任何先前设置的process.exitCode。
process.on('uncaughtException', (err, origin) => {
console.log(err);
});
UncaughtException是“非常粗糙的机制”(确实如此),而域现在已经被弃用。然而,我们仍然需要一些机制来捕获(逻辑)域周围的错误。这个库:
https://github.com/vacuumlabs/yacol
可以帮助您完成这个任务。只需稍微多写一些代码,您就可以在整个代码中拥有良好的域语义!
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);
});
UncaughtException
并不是推荐的方法,根据http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception的说明。 - undefined
uncaughtException
是不好的,而应该使用Cluster
中的Domain
,这样,如果一个用户遇到异常,只有他的线程从集群中删除并为他创建新的线程。而且你也不需要重新启动Node服务器。另一方面,如果你使用uncaughtException
,每当你的任何用户遇到问题时,你都必须重新启动服务器。因此,请使用带有Cluster的Domain。 - Airydomain
被完全废弃和移除时,我们应该怎么办? - Jas