在 unhandledRejection 之后是否需要重新启动我的应用程序

Bob*_* JS 2 javascript node.js es6-promise

我有一个 nodeJS 应用程序(服务器)并使用了一些 3rd 方 npm 模块。同样在我的应用程序中,我有以下代码:

process.on("unhandledRejection", (reason, promise) => {
    console.error(`Unhandled Rejection at: ${promise} reason: ${reason}`);
    restartApp(); // ? Is this a must action?
});
Run Code Online (Sandbox Code Playgroud)

似乎并非所有承诺都被正确拒绝,在 3rd 方模块中,也可能在我的代码中。我知道这是使用此事件处理程序的最后一个资源。

捕获此未处理拒绝事件后的问题,是否需要重新启动我的应用程序?

Ter*_*nox 5

将错误分为两大类很有用:操作错误和程序员错误。

操作错误是正确编写的程序遇到的(不可避免的)运行时问题,例如磁盘已满、网络连接丢失等。

程序员错误是由代码中的错误或疏忽引起的,无法处理,因为它们会导致程序进入未知状态,它们可能在您的代码您正在调用的模块中。

程序员错误的最佳实践是立即崩溃。您应该使用重启程序(见下文)运行您的程序,它会在发生崩溃时自动重启程序。有了重新启动器,崩溃是在遇到瞬时程序员错误时恢复可靠服务的最快方法。

如果错误是操作错误,尝试恢复或重试操作可能是有意义的(如果这有意义的话)。例如,如果您收到 400 个错误,则没有必要重试 REST 请求,但如果您收到 500 个错误(系统可能会恢复),则可能会有。

在这个非常有用的指南中查看更多信息:https : //www.joyent.com/node-js/production/design/errors

在您的特定情况下,您正在处理 unhandledRejection,这意味着应用程序处于未定义状态......与 unhandledException 非常相似,最好的办法是清理任何需要完成的事情,然后退出或重新启动, 同时记录错误(这非常重要!错误是每天、每小时还是每分钟发生?)

我建议使用进程监视器,例如PM2Forever。当您因错误退出时,它们可以自动重新启动,并执行许多其他很酷的事情,例如记录这些事件。

这是 Heroku 关于同一主题的另一个不错的指南:https : //blog.heroku.com/best-practices-nodejs-errors

博主 (Julián Duque) 甚至汇总了一些处理这些事件的最佳实践:https : //blog.heroku.com/best-practices-nodejs-errors#putting-it-all-together

这看起来有点像这样:

const http = require('http')
const terminate = require('./terminate')
const server = http.createServer(...)

const exitHandler = terminate(server, {
  coredump: false,
  timeout: 500
})

process.on('uncaughtException', exitHandler(1, 'Unexpected Error'))
process.on('unhandledRejection', exitHandler(1, 'Unhandled Promise'))
process.on('SIGTERM', exitHandler(0, 'SIGTERM'))
process.on('SIGINT', exitHandler(0, 'SIGINT'))
Run Code Online (Sandbox Code Playgroud)

终止模块:

function terminate (server, options = { coredump: false, timeout: 500 })    {
  // Exit function
  const exit = code => {
    options.coredump ? process.abort() : process.exit(code)
  }

  return (code, reason) => (err, promise) => {
    if (err && err instanceof Error) {
    // Log error information, use a proper logging library here :)
    console.log(err.message, err.stack)
    }

    // Attempt a graceful shutdown
    server.close(exit)
    setTimeout(exit, options.timeout).unref()
  }
}

module.exports = terminate
Run Code Online (Sandbox Code Playgroud)

我认为这种对这些事件进行管理、集中处理的方式是正确的方法。