Wie kann ich eine Instanz von ExpressJS programmgesteuert zum Testen herunterfahren?

105

Ich versuche herauszufinden, wie eine Instanz von Express heruntergefahren werden kann. Grundsätzlich möchte ich die Umkehrung des .listen(port)Anrufs - wie kann ich einen Express-Server dazu bringen, das Abhören zu stoppen, den Port freizugeben und sauber herunterzufahren?

Ich weiß, dass dies eine seltsame Frage zu sein scheint. Hier ist der Kontext. Vielleicht gibt es einen anderen Weg, dies zu erreichen, und ich denke falsch darüber nach. Ich versuche, ein Testframework für meine socket.io/nodejs-App einzurichten. Es ist eine einseitige App, also in meinen Testskripten (ich verwende MochaIch möchte in der Lage sein, den Server zu starten, Tests dagegen durchzuführen und dann den Server herunterzufahren. Ich kann dies umgehen, indem ich davon ausgehe, dass entweder der Server vor dem Start des Tests eingeschaltet ist oder dass einer der Tests den Server startet und jeder nachfolgende Test davon ausgeht, dass er aktiv ist, aber das ist wirklich chaotisch. Ich würde es sehr bevorzugen, wenn jede Testdatei eine Serverinstanz mit den entsprechenden Einstellungen startet und diese Instanz dann herunterfährt, wenn die Tests beendet sind. Das heißt, es gibt keine seltsamen Abhängigkeiten beim Ausführen des Tests und alles ist sauber. Es bedeutet auch, dass ich Start- / Abschalttests durchführen kann.

Also, irgendwelche Ratschläge, wie das geht? Ich habe darüber nachgedacht, Ausnahmen manuell auszulösen, um sie zu beenden, aber das scheint chaotisch. Ich habe Express-Dokumente und -Quelle durchsucht, kann aber anscheinend keine Methode finden, mit der der Server heruntergefahren werden kann. Es könnte auch etwas in socket.io dafür geben, aber da der Socket-Server nur an den Express-Server angeschlossen ist, denke ich, dass dies auf der Express-Ebene geschehen muss.

zogww
quelle

Antworten:

155

Die Dinge haben sich geändert, weil der Express-Server nicht mehr vom Knoten-HTTP-Server erbt. Glücklicherweise gibt app.listen die Serverinstanz zurück.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};
Reiches Apodaca
quelle
23
Bei Mokka-Tests, bei denen Sie ('App') benötigen, erweitere ich das App-Objekt: app.server = app.listen (3000); also kann ich später sagen: var app = require ('./ app'); app.server.close ();
Jack Chi
2
Wenn Sie den Server testen, besuchen Sie github.com/visionmedia/supertest, damit Sie testen können, ohne den tatsächlichen Server zu starten
Lukas Liesis,
Ich würde auch vorschlagen, dass Sie den erledigten Rückruf an weiterleiten, server.close()wenn Sie dies aus einem Hook heraus aufrufen.
Ullauri
Hinweis: Es gibt einen großen Unterschied zwischen 'app', der Express-Anwendungsinstanz, und dem Rückgabewert von 'app.listen', der zugrunde liegenden nativen HTTP-Serverinstanz mit der Methode 'close'. @ JackChi hat dies oben angedeutet.
Ajxs
Verursacht dies nicht Probleme mit offenen Client-Sockets, die offen bleiben?
Cameron Tacklind
18

Verwenden Sie app.close(). Vollständiges Beispiel:

var app = require('express').createServer();
app.get('/', function(req, res){
  res.send('hello world');
});
app.get('/quit', function(req,res) {
  res.send('closing..');
  app.close();
});
app.listen(3000);

Rufen Sie app.close()innerhalb des Rückrufs an, wenn die Tests beendet wurden. Denken Sie jedoch daran, dass der Prozess noch ausgeführt wird (obwohl er nicht mehr zuhört).

Wenn Sie danach den Vorgang beenden müssen, rufen Sie an process.exit(0).

Links:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (Gleiches gilt für)

process.exit: http://nodejs.org/docs/latest/api/process.html#process.exit

Srijan Choudhary
quelle
1
Perfekt, genau das, wonach ich gesucht habe. Ich glaube, ich habe es in Express nicht gefunden, weil sie den http-Server des Kernknotens erweitert haben, was ich nicht ganz verstanden habe. Vielen Dank!
zog
Danke Srijan, das hat mir auch geholfen
Adam Hopkinson
Ist das noch wahr? express.createServer wird als veraltet markiert und gibt einen Fehler aus, der besagt, dass die App nicht mehr vom Server von http.js erbt
Frank Schwieterman
4
Dies gilt nicht seit Express 3.
Gprasant
4
Es ist meiner Meinung nach keine gute Idee, eine URL zum Schließen eines solchen Servers bereitzustellen.
Shime
2

Ich habe eine Variation von "Wie man einen HTTP-Server beendet" viele Male auf verschiedenen beantwortet Unterstützungskanäle. Leider konnte ich keine der vorhandenen Bibliotheken empfehlen, da sie auf die eine oder andere Weise fehlen . Ich habe seitdem ein Paket zusammengestellt, das (glaube ich) alle Fälle behandelt, die von einer ordnungsgemäßen Beendigung des HTTP-Servers erwartet werden.

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

Der Hauptvorteil von http-terminator ist, dass:

  • Es gibt keine Node.js-API für Affen-Patches
  • Es werden sofort alle Sockets ohne angehängte HTTP-Anforderung zerstört
  • Es ermöglicht ein ordnungsgemäßes Timeout für Sockets mit laufenden HTTP-Anforderungen
  • HTTPS-Verbindungen werden ordnungsgemäß verarbeitet
  • Es informiert Verbindungen mit Keep-Alive darüber, dass der Server heruntergefahren wird, indem eine Verbindung hergestellt wird: Header schließen
  • Der Node.js-Prozess wird nicht beendet

Verwendung mit Express.js:

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

const app = express();

const server = app.listen();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();
Gajus
quelle
0
//... some stuff 

var server = app.listen(3000);
server.close();
alex dykyі
quelle
-1

Sie können dies einfach tun, indem Sie ein Bash-Skript schreiben, um den Server zu starten, die Tests auszuführen und den Server zu stoppen. Dies hat den Vorteil, dass Sie einen Alias ​​für dieses Skript erstellen können, um alle Ihre Tests schnell und einfach auszuführen.

Ich verwende solche Skripte für meinen gesamten kontinuierlichen Bereitstellungsprozess. Sie sollten sich Jon Rohans Dead Simple Git Workflow ansehen, um einen Einblick zu erhalten.

Josh Smith
quelle
2
Dies würde funktionieren, aber ich würde wenn möglich eine bashfreie Lösung bevorzugen. Vielleicht ist es eine dumme Präferenz, aber ich möchte den Server über den Testkontext starten / stoppen, da dies das Schreiben von serverkonfigurationsspezifischen Tests + Start- / Herunterfahren-Tests erleichtert. Außerdem wird nicht die Indirektion eingeführt, dass serverbezogene Tests über ein separates Skript ausgeführt werden müssen.
zog
Warum schreiben Sie umgebungsspezifische Tests? Vielleicht irre ich mich, aber das scheint mir eine schlechte Praxis zu sein. Ich würde versuchen, bei Ihren Tests umweltunabhängig zu bleiben, da Sie möchten, dass Ihre Tests unabhängig von der Entwicklungsumgebung in Ihrem Team funktionieren.
Josh Smith
Ich mache hier nichts Umweltspezifisches, glaube ich nicht. Es wird eine Handvoll verschiedener Startoptionen für den Server geben (wie das Lesen von Konfigurationsoptionen aus einer Datei, das Laden des Status aus einem Datenspeicher usw.), die im selben Framework getestet werden könnten, in dem ich alles andere teste. Ich hätte auch gerne Tests, bei denen beispielsweise der Server heruntergefahren, wieder hochgefahren und sichergestellt wird, dass er dabei nicht den Status verliert. Das ist einfacher, wenn ich es programmgesteuert vom Knoten aus tun kann, als auch Code in Bash zu testen.
zog
Sie würden Ihren Testcode nicht in bash selbst platzieren. Sie starten einfach den Server und führen die Tests über das Skript aus, genau wie Sie es selbst in der Befehlszeile tun würden. Es gibt dort keine wirklich besondere Magie.
Josh Smith