我继承了一个有点乱的 node.js/Express 应用程序。它经常且相当随机地卡住并且在重新启动之前不响应任何请求。

我怀疑应用程序中的某些内容正在阻塞并且要么陷入循环中,要么在没有使用适当的异步技术的情况下向外部 api 发出请求,并且永远不会得到响应并且永远不会在巫婆点超时服务器只是停止响应但没有崩溃。

我显然想找到罪魁祸首代码并解决问题,但同时我想找到一种方法来在服务器停止响应时自动重新启动服务器。

为了在本地测试解决方案(因为我目前不知道真正的罪魁祸首),我创建了以下 Express 路由,它模拟了我得到的确切行为。

app.get('/block-block-block', function (req, res){
  for(;;) {}
};

我的问题是让上述路由被命中(这会立即停止服务器响应任何事情),有没有办法在内部检测 Node 中的阻塞并重新启动或关闭?如果不是,检查服务器何时没有响应并重新启动它的好解决方案是什么?

我所做的大多数搜索都让我找到了 foreverPM2 之类的工具。如果您的应用程序崩溃,这些工作很好,但当应用程序被 radomley 阻塞时,我真的看不到任何重新启动的功能。

最佳答案

我想出了如何使用 native Node 功能解决这个问题。 Migg 的回答很好,并引导我朝着正确的方向前进,但它仍然没有显示如何在事件循环完全阻塞时自动重新启动。

诀窍是使用 Node 的原生 child_process 模块和 fork method 从另一个 Node 实例启动服务器,并让该实例 ping 服务器以获取响应,当它卡住时重新启动它。这类似于 Forever 和 PM2 的工作方式。很难相信没有一种简单的方法可以使用这两个库中的任何一个来实现这一点,但这就是您可以天真地做到这一点的方法。

我已经对这段代码进行了大量评论,以指出一切都在做什么。另请注意,我使用的是 ES2015 的 Arrow Functions. 如果您不熟悉,请阅读它们。

var fork = require('child_process').fork;
var server, heartbeat;

function startServer () {
  console.log('Starting server');
  server = fork('server');

  //when the server goes down restart it
  server.on('close', (code) => {
    startServer();
  });

  //when server sends a heartbeat message save it
  server.on('message', (message) => {
    heartbeat = message ? message.heartbeat : null;
  });

  //ask the server for a heartbeat
  server.send({request: 'heartbeat'});

  //wait 5 seconds and check if the server responded
  setTimeout(checkHeartbeat, 5000);
}

function checkHeartbeat() {
  if(heartbeat) {
    console.log('Server is alive');

    //clear the heart beat and send request for a new one
    heartbeat = null;
    server.send({request: 'heartbeat'});

    //set another hearbeat check
    setTimeout(checkHeartbeat, 5000);

  } else {
    console.log('Server looks stuck...killing');
    server.kill();
  }
}

startServer();

请务必使用您要运行的任何 Node 应用程序更改 server.js。

现在在您的服务器上添加以下内容以响应心跳请求。
//listen and respond to heartbeat request from parent
process.on('message', (message) => {
  if(message && message.request === 'heartbeat') {
    process.send({heartbeat: 'thump'});
  }
});

最后添加一个超时来测试它是否有效(不适用于生产!)
//block the even loop after 30 seconds
setTimeout(() => {
  for(;;){}
}, 30000);

关于Node.js:自动重启没有响应的 Node 服务器的好方法是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35185522/

10-09 20:22
查看更多