web-dev-qa-db-ja.com

Node.js http(s)サーバーをすぐにシャットダウンするにはどうすればよいですか?

Http(s)サーバーを含むNode.jsアプリケーションがあります。

特定のケースでは、このサーバーをプログラムでシャットダウンする必要があります。私が現在していることは、そのclose()関数を呼び出すことですが、キープアライブ接続が最初に終了するまで待機するため、これは役に立ちません。

したがって、基本的に、これはサーバーをシャットダウンしますが、最小待機時間は120秒です。しかし、サーバーがすぐにシャットダウンするようにしたい-これは、現在処理されているリクエストを分割することを意味する場合でも。

私にできないことは簡単です

_process.exit();
_

サーバーはアプリケーションの一部にすぎず、残りのアプリケーションは実行したままにする必要があるためです。私が探しているのは、概念的にserver.destroy();などのようなものです。

どうすればこれを達成できますか?

PS:接続のキープアライブタイムアウトは通常必要であるため、この時間を短縮するための実行可能なオプションではありません。

50
Golo Roden

トリックは、新しい接続のソケットを提供するサーバーの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秒後にサーバーを閉じます。接続が確立されていない場合、サーバーはすぐにシャットダウンします。

接続が確立され、まだ開いている場合、破棄されます。すでに自然に死んでいた場合、その時点ではメッセージのみが出力されます。

65
Golo Roden

接続を追跡したり、強制的に閉じたりすることなく、これを行う方法を見つけました。 Nodeバージョン間またはこれにマイナスの影響があるかどうかはわかりませんが、私がやっていることに対して完全にうまくいくようです。 setImmediateメソッドを呼び出した直後にcloseを使用して「閉じる」イベント。これは次のように機能します。

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

少なくとも私にとっては、これによりポートが解放され、コールバックが呼び出されるまでに新しいHTTP(S)サービスを開始できるようになります(ほとんど瞬時に)。既存の接続は開いたままです。 Let's Encrypt証明書を更新した後、これを使用してHTTPSサービスを自動的に再起動します。

17
Jonathan Gray

サーバーを閉じた後もプロセスを維持する必要がある場合は、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();
    });
}
_

基本的に、サーバーが使用するソケットは、実際にリクエストを処理している間のみプロセスを有効に保ちます。 (Keep-Alive接続のため)彼らがただそこに座っている間に、server.close()を呼び出すと、プロセスを維持しているプロセスが他にない限り、プロセスを閉じます。サーバーを閉じた後、正常なシャットダウンの一部として他のことを行う必要がある場合は、process.on('beforeExit', callback)にフックして、正常なシャットダウン手順を完了できます。

8
Joshua Wise

https://github.com/isaacs/server-destroy ライブラリは、(開かれた接続を追跡して破棄することにより)質問で望まれる動作を持つサーバーをdestroy()する簡単な方法を提供します他の回答で説明されているように、サーバー上のそれらはそれぞれ破棄します)。

7
ploer

他の人が言ったように、解決策は、開いているすべてのソケットを追跡し、それらを手動で閉じることです。私のノードパッケージ killable はこれをあなたのためにできます。例(エクスプレスを使用しますが、任意のhttp.serverインスタンス):

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);
4
marten-de-vries

接続をシャットダウンするシャットダウンを実行するためのさらに別のnodejsパッケージ: http-shutdown 。これは、執筆時点(2016年9月)で合理的に維持されているようで、NodeJS 6.xで機能しました。

ドキュメントから

使用法

現在、このライブラリを使用するには2つの方法があります。 1つ目は、サーバーオブジェクトの明示的なラッピングです。

// 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.');
});

2つ目は、プロトタイプ機能をサーバーオブジェクトに暗黙的に追加することです。

// .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.');
});
3
Bruno Grieder

私の最善の推測は、接続を手動で強制終了することです(つまり、ソケットを強制的に閉じることです)。

理想的には、これはサーバーの内部を掘り下げて、手でソケットを閉じることによって行われるべきです。または、同じことを行うシェルコマンドを実行することもできます(サーバーに適切な特権&cがある場合)。

2
Morten Siebuhr
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();
  }
})
0
vapour