【问题标题】:Express.js app not shutting down cleanly with server.close()Express.js 应用程序未使用 server.close() 完全关闭
【发布时间】:2015-09-09 02:14:48
【问题描述】:

我正在尝试在应用关闭时正确关闭 MongoDB 连接。代码如下:

var express = require('express')
  , http = require('http')
  , mongoose = require('mongoose')
  , path = require('path');

var app = express();

app.set('port', process.env.PORT || 3000);

mongoose.connect('mongodb://localhost/test');

// some post and get handlers etc. (removed for shorter output)

var server = app.listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
});

function cleanup () {
    server.close(function () {
        console.log("Closed out remaining connections.");
        mongoose.connection.close();
        process.exit();
    });

    setTimeout( function () {
        console.error("Could not close connections in time, forcing shut down");
        process.exit(1);
    }, 30*1000);
}

process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

当应用程序第一次启动时,一切都很好并且工作正常。当我在它启动后立即点击Ctrl-c 时,它会干净地关闭并显示Closed out remaining connections. 消息。但是,一旦应用程序与数据库交互甚至提供静态页面,然后我尝试将其关闭,它就会退出并出现以下错误:

net.js:1225
    throw new Error('Not running');
          ^
Error: Not running
    at Server.close (net.js:1225:11)
    at process.cleanup (<...>/app.js:77:12)
    at process.EventEmitter.emit (events.js:92:17)
    at Signal.wrap.onsignal (node.js:756:46)
22 Aug 15:15:28 - [nodemon] exiting

任何想法是什么导致了这个错误以及我该如何解决它?

【问题讨论】:

  • 在提供静态页面后,是否需要按两次 ctrl-c 才能看到此错误,而不是在未完成提供服务的情况下。
  • 不,只有一个Ctrl-c
  • 服务器没有关闭的原因是因为有剩余的套接字是打开的。您必须跟踪它们并一一关闭它们。要更好地了解该过程并了解如何管理套接字,请阅读dev.to/gajus/how-to-terminate-a-http-server-in-node-js-ofk

标签: node.js mongodb express application-shutdown


【解决方案1】:

调用 server.close 时,会检查两个属性。

   handle<tcp handle>
   connections

负责这个错误的server.close的代码片段;

  if (!this._handle) {
    // Throw error. Follows net_legacy behaviour.
    throw new Error('Not running');
  }

只有当handle===null 和connections ===0 时,传递给close 的回调才会被调用。

案例:服务器启动并发送信号但没有服务。

在调用关闭之前;

  handle === TCP handle.
  connection===0;

关闭后 句柄===空; 连接===0;

回调被调用。

案例:服务器启动并在请求服务器之后发送信号。

在调用关闭之前;

  handle === TCP.handle;
  connection===1;

关闭后 处理 === 空; 连接===1;

没有触发回调。

第二次按 ctrl-c

在调用关闭之前;

  handle === null;
  connection===1;

由于 handle===null ,检查会抛出您看到的错误。

【讨论】:

  • 那么如何确保所有连接都正确关闭?我以为只需要关闭数据库连接?
  • 一种简单的方法,在清理功能中,将以下语句放在 server.close(fn) server.connections=0;
  • 谢谢,这似乎有效。但是,server.connections 似乎已被弃用。当我关闭应用程序时返回以下消息:connections property is deprecated. Use getConnections() method。知道如何使用这种方法来实现与上面指定的相同的事情吗?
  • 尝试 server._connections=0
【解决方案2】:

您的服务器打开连接的原因是因为您正在发送Connection: keep-alive 标头。

摩根的回答干净利落地关闭了服务器上的所有连接,断开了所有客户端。

如果您只是在测试您的应用程序并希望在测试之前/之后彻底关闭它,我建议发送 Connection: close 标头和 server.close() 将按预期工作。

【讨论】:

    【解决方案3】:

    我不认为设置 server._connections = 0 实际上会关闭连接。它只是满足执行回调的条件。

    你可能想尝试这样的事情:

    // Everything else how you had it before ...
    
    var sockets = [];
    
    server.on('connection', function(socket) {
      sockets.push(socket);
    });
    
    function cleanup () {
      server.close(function () {
        console.log("Closed out remaining connections.");
         // mongoose.connection.close(); Might want to comment this out
        process.exit();
      });
    
      // Add this part to manually destroy all the connections.
      sockets.forEach(function(socket) {
        socket.destroy();
      });
    
      // setTimeout() ...
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-13
    • 2014-02-03
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多