web-dev-qa-db-de.com

Wie kann ich einen Node.js http (s) Server sofort herunterfahren?

Ich habe eine Node.js-Anwendung, die einen http-Server enthält.

In einem bestimmten Fall muss ich diesen Server programmgesteuert herunterfahren. Momentan rufe ich die Funktion close() auf, was jedoch nicht hilft, da darauf gewartet wird, dass alle Verbindungen, die am Leben bleiben, zuerst beendet werden.

Im Grunde genommen wird der Server dadurch heruntergefahren, jedoch erst nach einer Mindestwartezeit von 120 Sekunden. Ich möchte jedoch, dass der Server sofort heruntergefahren wird - auch wenn dies bedeutet, dass die aktuell verarbeiteten Anforderungen nicht mehr erfüllt werden.

Was ich nicht kann ist ein einfaches

process.exit();

da der Server nur ein Teil der Anwendung ist, sollte der Rest der Anwendung weiterhin ausgeführt werden. Was ich suche, ist konzeptionell etwas wie server.destroy(); oder so ähnlich.

Wie könnte ich das erreichen?

PS: Das Keep-Alive-Timeout für Verbindungen ist normalerweise erforderlich, daher ist es keine sinnvolle Option, diese Zeit zu verkürzen.

50
Golo Roden

Der Trick ist, dass Sie das Ereignis connection des Servers abonnieren müssen, das Ihnen den Socket der neuen Verbindung gibt. Sie müssen sich diesen Socket merken und später, direkt nachdem Sie server.close() aufgerufen haben, diesen Socket mit socket.destroy() zerstören.

Darüber hinaus müssen Sie das Ereignis close des Sockets abhören, um es aus dem Array zu entfernen, wenn es auf natürliche Weise verlassen wird, da das Keep-Alive-Timeout abläuft.

Ich habe eine kleine Beispielanwendung geschrieben, mit der Sie dieses Verhalten demonstrieren können:

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

Grundsätzlich müssen Sie einen neuen HTTP-Server starten, von 10 bis 0 zählen und den Server nach 10 Sekunden schließen. Wenn keine Verbindung hergestellt wurde, wird der Server sofort heruntergefahren.

Wenn eine Verbindung hergestellt wurde und sie noch offen ist, wird sie zerstört. Wenn es natürlich schon gestorben ist, wird zu diesem Zeitpunkt nur eine Nachricht ausgedruckt.

65
Golo Roden

Ich habe einen Weg gefunden, dies zu tun, ohne die Verbindungen im Auge zu behalten oder sie zu schließen. Ich bin mir nicht sicher, wie zuverlässig es in allen Node) - Versionen ist oder ob dies negative Konsequenzen hat, aber es scheint für das, was ich tue, völlig in Ordnung zu sein "close" -Ereignis mit setImmediate direkt nach dem Aufruf der close -Methode.

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

Zumindest für mich bedeutet dies, dass der Port freigegeben wird, sodass ich einen neuen HTTP (S) -Dienst zum Zeitpunkt des Aufrufs des Rückrufs starten kann (was praktisch sofort geschieht). Bestehende Verbindungen bleiben offen. Ich verwende dies, um den HTTPS-Dienst nach der Erneuerung eines Let's Encrypt-Zertifikats automatisch neu zu starten.

17
Jonathan Gray

Wenn Sie den Prozess nach dem Schließen des Servers am Leben erhalten müssen, ist die Lösung von Golo Roden wahrscheinlich die beste.

Wenn Sie den Server jedoch im Rahmen eines ordnungsgemäßen Herunterfahrens des Prozesses schließen, benötigen Sie Folgendes:

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

Grundsätzlich halten die Sockets, die Ihr Server verwendet, den Prozess nur am Leben, während eine Anfrage tatsächlich bearbeitet wird. Während sie nur untätig da sitzen (wegen einer Keep-Alive-Verbindung), wird ein Aufruf von server.close() den Prozess schließen, solange nichts anderes den Prozess am Leben hält. Wenn Sie im Rahmen des ordnungsgemäßen Herunterfahrens nach dem Schließen des Servers andere Aktionen ausführen müssen, können Sie sich in process.on('beforeExit', callback) einbinden, um die ordnungsgemäßen Herunterfahrvorgänge abzuschließen.

8
Joshua Wise

Die Bibliothek https://github.com/isaacs/server-destroy bietet eine einfache Möglichkeit, destroy() einen Server mit dem in der Frage gewünschten Verhalten zu finden (indem geöffnete Verbindungen verfolgt und zerstört werden) Jeder von ihnen auf dem Server zu zerstören, wie in anderen Antworten beschrieben).

7
ploer

Wie andere bereits gesagt haben, besteht die Lösung darin, alle offenen Steckdosen im Auge zu behalten und manuell zu schließen. Mein Knotenpaket killable kann dies für Sie tun. Ein Beispiel (mit express, aber Sie können use killable für jede Instanz von http.server Aufrufen):

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

Ein weiteres NodeJS-Paket zum Beenden von Verbindungen: http-shutdown , das zum Zeitpunkt des Schreibens (Sept. 2016) einigermaßen gepflegt zu sein scheint und für mich auf NodeJS 6.x funktioniert hat

Aus der Dokumentation

Verwendung

Derzeit gibt es zwei Möglichkeiten, diese Bibliothek zu verwenden. Das erste ist das explizite Umschließen des Server-Objekts:

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

Die zweite besteht darin, dem Server-Objekt implizit eine Prototyp-Funktionalität hinzuzufügen:

// .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

Ich würde am besten raten, die Verbindungen manuell zu trennen (d. H. Die Sockets zwangsweise zu schließen).

Im Idealfall sollten Sie dazu in die Interna des Servers greifen und die Sockel von Hand schließen. Alternativ könnte man einen Shell-Befehl ausführen, der dasselbe tut (vorausgesetzt, der Server verfügt über die entsprechenden Berechtigungen usw.).

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