63

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

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

したがって、基本的に、これはサーバーをシャットダウンしますが、120秒の最小待機時間の後でのみです。ただし、サーバーをすぐにシャットダウンする必要があります。これは、現在処理されている要求との分割を意味する場合でも同様です。

私ができないのは単純なことです

process.exit();

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

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

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

4

10 に答える 10

78

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

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

于 2013-01-31T22:52:20.320 に答える
23

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

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

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

于 2016-04-24T23:27:24.487 に答える
13

サーバーを閉じた後もプロセスを存続させる必要がある場合は、GoloRodenのソリューションがおそらく最適です。

ただし、プロセスの正常なシャットダウンの一部としてサーバーを閉じる場合は、次のようにする必要があります。

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)てグレースフルシャットダウン手順を完了することができます。

于 2015-07-19T19:05:24.493 に答える
8

https://github.com/isaacs/server-destroyライブラリは、質問で必要な動作を備えたサーバーへの簡単な方法を提供します(destroy()他の回答で説明されているように、開いている接続を追跡し、サーバーの破棄で各接続を破棄します)。

于 2015-01-13T18:37:12.043 に答える
6

他の人が言っているように、解決策はすべての開いているソケットを追跡し、それらを手動で閉じることです。私のノードパッケージ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);
于 2014-12-21T16:26:44.710 に答える
3

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

ドキュメントから

使用法

現在、このライブラリを使用する方法は2つあります。1つ目は、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.');
});

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.');
});
于 2016-09-29T11:34:17.800 に答える
2

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

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

于 2013-01-31T14:01:17.990 に答える
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();
  }
})

于 2019-04-26T07:56:19.740 に答える
0

サポートチャネルで「HTTPサーバーを終了する方法」のバリエーションに何度も答えました。残念ながら、既存のライブラリは何らかの形で不足しているため、お勧めできませんでした。それ以来、(私が信じている)正常なHTTPサーバーの終了に期待されるすべてのケースを処理するパッケージをまとめました。

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

http-terminatorの主な利点は次のとおりです。

  • Node.jsAPIにモンキーパッチを適用しません
  • HTTPリクエストが添付されていないすべてのソケットをすぐに破棄します
  • 進行中のHTTPリクエストでソケットに適切なタイムアウトを許可します
  • HTTPS接続を適切に処理します
  • 接続を設定することにより、サーバーがシャットダウンしていることをkeep-aliveを使用して接続に通知します。closeヘッダー
  • Node.jsプロセスは終了しません

使用法:

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

const server = http.createServer();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();

于 2020-01-20T02:45:01.197 に答える
-5

process.exit(code); //成功の場合はコード0、失敗の場合はコード1

于 2016-05-17T19:38:15.280 に答える