如何立即关闭Node.js http(s)服务器?

时间:2013-01-31 13:13:22

标签: node.js http connection keep-alive

我有一个包含http(s)服务器的Node.js应用程序。

在特定情况下,我需要以编程方式关闭此服务器。我目前正在做的是调用它的close()函数,但这没有用,因为它等待任何保持活动的连接首先完成。

所以,基本上,这会关闭服务器,但只能在120秒的最小等待时间之后。但我希望服务器立即关闭 - 即使这意味着与当前处理的请求分手。

我不能做的是一个简单的

process.exit();

因为服务器只是应用程序的一部分,应用程序的其余部分应该保持运行。我正在寻找的是概念性的东西,例如server.destroy();或类似的东西。

我怎么能实现这个目标?

PS:通常需要连接的保持活动超时,因此减少这个时间不是一个可行的选择。

10 个答案:

答案 0 :(得分:64)

诀窍是您需要订阅服务器的connection事件,该事件为您提供新连接的套接字。您需要记住此套接字,稍后在调用server.close()后直接使用socket.destroy()销毁该套接字。

此外,您需要侦听套接字的close事件,如果它自然离开,则将其从数组中删除,因为它的保持活动超时确实已用完。

我编写了一个小样本应用程序,可用于演示此行为:

// Create a new server on port 4000
var http = require('http');
var server = http.createServer(function (req, res) {
  res.end('Hello world!');
}).listen(4000);

// Maintain a hash of all connected sockets
var sockets = {}, nextSocketId = 0;
server.on('connection', function (socket) {
  // Add a newly connected socket
  var socketId = nextSocketId++;
  sockets[socketId] = socket;
  console.log('socket', socketId, 'opened');

  // Remove the socket when it closes
  socket.on('close', function () {
    console.log('socket', socketId, 'closed');
    delete sockets[socketId];
  });

  // Extend socket lifetime for demo purposes
  socket.setTimeout(4000);
});

// Count down from 10 seconds
(function countDown (counter) {
  console.log(counter);
  if (counter > 0)
    return setTimeout(countDown, 1000, counter - 1);

  // Close the server
  server.close(function () { console.log('Server closed!'); });
  // Destroy all open sockets
  for (var socketId in sockets) {
    console.log('socket', socketId, 'destroyed');
    sockets[socketId].destroy();
  }
})(10);

基本上,它的作用是启动一个新的HTTP服务器,从10到0计数,并在10秒后关闭服务器。如果尚未建立连接,则服务器立即关闭。

如果已建立连接并且它仍处于打开状态,则会将其销毁。 如果它已经自然死亡,那么此时只打印出一条消息。

答案 1 :(得分:17)

我找到了一种方法来做到这一点,而无需跟踪连接或不得不强制关闭。我不确定它在Node版本中的可靠性如何,或者如果对此有任何负面影响,但它似乎对我正在做的事情完全正常。诀窍是在调用setImmediate方法后立即使用close发出“关闭”事件。这样工作原理如下:

server.close(callback);
setImmediate(function(){server.emit('close')});

至少对我来说,这最终会释放端口,这样我就可以在调用回调时启动一个新的HTTP(S)服务(这几乎是即时的)。现有连接保持开放。我正在使用它在续订Let的加密证书后自动重启HTTPS服务。

答案 2 :(得分:8)

如果您需要在关闭服务器后保持流程处于活动状态,那么Golo Roden的解决方案可能是最好的。

但是,如果您正在关闭服务器作为正常关闭流程的一部分,那么您只需要:

var server = require('http').createServer(myFancyServerLogic);

server.on('connection', function (socket) {socket.unref();});
server.listen(80);

function myFancyServerLogic(req, res) {
    req.connection.ref();

    res.end('Hello World!', function () {
        req.connection.unref();
    });
}

基本上,服务器使用的套接字只会使进程在实际提供请求时保持活动状态。虽然他们只是懒散地坐在那里(因为保持活跃的连接),但是对server.close()的调用将关闭该过程,只要没有其他任何东西保持该过程活着。如果您需要在服务器关闭后执行其他操作,作为正常关闭的一部分,您可以挂钩process.on('beforeExit', callback)以完成正常的关闭过程。

答案 3 :(得分:7)

https://github.com/isaacs/server-destroy库提供了一种简单的方法destroy()服务器具有问题所需的行为(通过跟踪打开的连接并在服务器销毁时销毁它们,如其他答案中所述)。

答案 4 :(得分:4)

正如其他人所说,解决方案是跟踪所有打开的套接字并手动关闭它们。我的节点包killable可以为您完成此操作。一个例子(使用express,但你可以在任何http.server实例上调用use killable):

var killable = require('killable');

var app = require('express')();
var server;

app.route('/', function (req, res, next) {
  res.send('Server is going down NOW!');

  server.kill(function () {
    //the server is down when this is called. That won't take long.
  });
});

var server = app.listen(8080);
killable(server);

答案 5 :(得分:3)

另一个nodejs包执行关闭查杀连接:http-shutdown,在编写本文时(2016年9月)似乎合理维护并在NodeJS 6.x上为我工作

来自文档

<强>用法

目前有两种方法可以使用此库。第一个是显式包装Server对象:

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    // Make sure that we are currently visible
    if (this.isVisible()) {
        // If we are becoming invisible, then...
        if (!isVisibleToUser) {

            // Save scroll state
            LinearLayoutManager layoutManager = ((LinearLayoutManager) mRecyclerView.getLayoutManager());
            YourActivity.scrollPositionIndex = layoutManager.findFirstVisibleItemPosition();

            View v = mRecyclerView.getChildAt(0);
            YourActivity.scrollPositionOffset = (v == null) ? 0 : (v.getTop() - mRecyclerView.getPaddingTop());

        } else {
            // Scroll to the saved position
            mLayoutManager.scrollToPositionWithOffset(YourActivity.scrollPositionIndex,
                    YourActivity.scrollPositionOffset);

            // Reset the value
            YourActivity.scrollPositionIndex = 0;
            YourActivity.scrollPositionOffset = 0;
        }
    }
}

第二个是隐式地将原型功能添加到Server对象:

// Create the http server
var server = require('http').createServer(function(req, res) {
  res.end('Good job!');
});

// Wrap the server object with additional functionality.
// This should be done immediately after server construction, or before you start listening.
// Additional functionailiy needs to be added for http server events to properly shutdown.
server = require('http-shutdown')(server);

// Listen on a port and start taking requests.
server.listen(3000);

// Sometime later... shutdown the server.
server.shutdown(function() {
  console.log('Everything is cleanly shutdown.');
});

答案 6 :(得分:2)

我最好的猜测是手动终止连接(即强行关闭它的套接字)。

理想情况下,这应该通过挖掘服务器的内部结构并手动关闭它的套接字来完成。或者,可以运行执行相同操作的shell命令(前提是服务器具有适当的权限&amp; c。)

答案 7 :(得分:0)

const Koa = require('koa')
const app = new Koa()

let keepAlive = true
app.use(async (ctx) => {
  let url = ctx.request.url

  // destroy socket
  if (keepAlive === false) {
    ctx.response.set('Connection', 'close')
  }
  switch (url) {
    case '/restart':
      ctx.body = 'success'
      process.send('restart')
      break;
    default:
      ctx.body = 'world-----' + Date.now()
  }
})
const server = app.listen(9011)

process.on('message', (data, sendHandle) => {
  if (data == 'stop') {
    keepAlive = false
    server.close();
  }
})

答案 8 :(得分:0)

我已经在不同的支持渠道上多次回答了“如何终止HTTP服务器”的变体。不幸的是,我不推荐任何现有的库,因为它们以一种或另一种方式lacking。从那以后,我整理了一个软件包(我相信)可以处理所有正常HTTP服务器终止的情况。

https://github.com/gajus/http-terminator

http-terminator的主要好处是:

  • 它没有猴子补丁Node.js API
  • 它会立即破坏所有套接字,而不会附加HTTP请求
  • 它允许对正在进行的HTTP请求的套接字进行适度超时
  • 它可以正确处理HTTPS连接
  • 它通过保持连接状态通过连接设置通知连接服务器正在关闭:close标头
  • 它不会终止Node.js进程

用法:

import http from 'http';
import {
  createHttpTerminator,
} from 'http-terminator';

const server = http.createServer();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();

答案 9 :(得分:-5)

process.exit(代码); //代码0代表成功,1代表失败