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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14626636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 17:04:23  来源:igfitidea点击:

How do I shutdown a Node.js http(s) server immediately?

node.jshttpconnectionkeep-alive

提问by Golo Roden

I have a Node.js application that contains an http(s) server.

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

In a specific case, I need to shutdown this server programmatically. What I am currently doing is calling its close()function, but this does not help, as it waits for any kept alive connections to finish first.

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

So, basically, this shutdowns the server, but only after a minimum wait time of 120 seconds. But I want the server to shutdown immediately - even if this means breaking up with currently handled requests.

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

What I can not do is a simple

我不能做的是一个简单的

process.exit();

as the server is only part of the application, and the rest of the application should remain running. What I am looking for is conceptually something such as server.destroy();or something like that.

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

How could I achieve this?

我怎么能做到这一点?

PS: The keep-alive timeout for connections is usually required, hence it is not a viable option to decrease this time.

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

回答by Golo Roden

The trick is that you need to subscribe to the server's connectionevent which gives you the socket of the new connection. You need to remember this socket and later on, directly after having called server.close(), destroy that socket using socket.destroy().

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

Additionally, you need to listen to the socket's closeevent to remove it from the array if it leaves naturally because its keep-alive timeout does run out.

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

I have written a small sample application you can use to demonstrate this behavior:

我编写了一个小示例应用程序,您可以使用它来演示这种行为:

// 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);

Basically, what it does is to start a new HTTP server, count from 10 to 0, and close the server after 10 seconds. If no connection has been established, the server shuts down immediately.

基本上,它所做的就是启动一个新的 HTTP 服务器,从 10 数到 0,然后在 10 秒后关闭服务器。如果没有建立连接,服务器会立即关闭。

If a connection has been established and it is still open, it is destroyed. If it had already died naturally, only a message is printed out at that point in time.

如果一个连接已经建立并且它仍然是打开的,它就会被销毁。如果它已经自然死亡,那么在那个时间点只打印一条消息。

回答by Jonathan Gray

I found a way to do this without having to keep track of the connections or having to force them closed. I'm not sure how reliable it is across Node versions or if there are any negative consequences to this but it seems to work perfectly fine for what I'm doing. The trick is to emit the "close" event using setImmediateright after calling the closemethod. This works like so:

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

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

At least for me, this ends up freeing the port so that I can start a new HTTP(S) service by the time the callback is called (which is pretty much instantly). Existing connections stay open. I'm using this to automatically restart the HTTPS service after renewing a Let's Encrypt certificate.

至少对我来说,这最终会释放端口,以便我可以在调用回调时启动新的 HTTP(S) 服务(这几乎是立即的)。现有连接保持打开状态。我正在使用它在更新 Let's Encrypt 证书后自动重新启动 HTTPS 服务。

回答by Joshua Wise

If you need to keep the process alive after closing the server, then Golo Roden's solution is probably the best.

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

But if you're closing the server as part of a graceful shutdown of the process, you just need this:

但是,如果您在正常关闭进程的过程中关闭服务器,则只需要以下内容:

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();
    });
}

Basically, the sockets that your server uses will only keep the process alive while they're actually serving a request. While they're just sitting there idly (because of a Keep-Alive connection), a call to server.close()will close the process, as long as there's nothing else keeping the process alive. If you need to do other things after the server closes, as part of your graceful shutdown, you can hook into process.on('beforeExit', callback)to finish your graceful shutdown procedures.

基本上,您的服务器使用的套接字只会在它们实际为请求提供服务时使进程保持活动状态。当他们只是闲坐在那里时(因为 Keep-Alive 连接),server.close()只要没有其他东西使进程保持活动状态,调用就会关闭进程。如果您需要在服务器关闭后做其他事情,作为您的正常关机的一部分,您可以使用 hookprocess.on('beforeExit', callback)来完成您的正常关机程序。

回答by ploer

The https://github.com/isaacs/server-destroylibrary provides an easy way to destroy()a server with the behavior desired in the question (by tracking opened connections and destroying each of them on server destroy, as described in other answers).

所述https://github.com/isaacs/server-destroy库提供了一种简单的方法来destroy()与所述问题所期望的行为的服务器(通过跟踪打开的连接和销毁它们中的每对服务器破坏,在其他的答案描述)。

回答by marten-de-vries

As others have said, the solution is to keep track of all open sockets and close them manually. My node package killablecan do this for you. An example (using express, but you can call use killable on any http.serverinstance):

正如其他人所说,解决方案是跟踪所有打开的套接字并手动关闭它们。我的 node 包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);

回答by Bruno Grieder

Yet another nodejs package to perform a shutdown killing connections: http-shutdown, which seems reasonably maintained at the time of writing (Sept. 2016) and worked for me on NodeJS 6.x

另一个用于执行关闭终止连接的 nodejs 包:http-shutdown,在撰写本文时(2016 年 9 月)似乎得到了合理维护,并在 NodeJS 6.x 上对我来说有效

From the documentation

从文档

Usage

用法

There are currently two ways to use this library. The first is explicit wrapping of the Server object:

目前有两种方法可以使用这个库。第一个是显式包装 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.');
});

The second is implicitly adding prototype functionality to the Server object:

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

// .extend adds a .withShutdown prototype method to the Server object
require('http-shutdown').extend();

var server = require('http').createServer(function(req, res) {
  res.end('God job!');
}).withShutdown(); // <-- Easy to chain. Returns the Server object

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

回答by Morten Siebuhr

My best guess would be to kill the connections manually (i.e. to forcibly close it's sockets).

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

Ideally, this should be done by digging into the server's internals and closing it's sockets by hand. Alternatively, one could run a shell-command that does the same (provided the server has proper privileges &c.)

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

回答by vapour

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();
  }
})

回答by Gajus

I have answered a variation of "how to terminate a HTTP server" many times on different node.jssupport channels. Unfortunately, I couldn't recommend any of the existing libraries because they are lackingin one or another way. I have since put together a package that (I believe) is handling all the cases expected of graceful HTTP server termination.

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

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

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

The main benefit of http-terminatoris that:

http-terminator的主要好处是:

  • it does not monkey-patch Node.js API
  • it immediately destroys all sockets without an attached HTTP request
  • it allows graceful timeout to sockets with ongoing HTTP requests
  • it properly handles HTTPS connections
  • it informs connections using keep-alive that server is shutting down by setting a connection: close header
  • it does not terminate the Node.js process
  • 它不会修补 Node.js API
  • 它立即销毁所有没有附加 HTTP 请求的套接字
  • 它允许对正在进行的 HTTP 请求的套接字进行正常超时
  • 它正确处理 HTTPS 连接
  • 它通过设置连接通知使用 keep-alive 服务器正在关闭的连接:关闭标头
  • 它不会终止 Node.js 进程

Usage:

用法:

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

const server = http.createServer();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();

回答by ManikandaPrabhu M

process.exit(code); // code 0 for success and 1 for fail

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