Comment arrêter par programme une instance d'ExpressJS à des fins de test?

106

J'essaie de comprendre comment arrêter une instance d'Express. Fondamentalement, je veux l'inverse de l' .listen(port)appel - comment faire pour qu'un serveur Express arrête d'écouter, libère le port et s'arrête proprement?

Je sais que cela semble être une question étrange, alors voici le contexte; peut-être y a-t-il une autre façon d'aborder cela et j'y pense mal. J'essaie de configurer un cadre de test pour mon application socket.io/nodejs. C'est une application d'une seule page, donc dans mes scripts de test (j'utilise Mocha, mais cela n'a pas vraiment d'importance) Je veux pouvoir démarrer le serveur, exécuter des tests dessus, puis arrêter le serveur. Je peux contourner ce problème en supposant que soit le serveur est allumé avant le début du test, soit en demandant à l'un des tests de démarrer le serveur et de faire en sorte que chaque test suivant suppose qu'il est opérationnel, mais c'est vraiment compliqué. Je préférerais de beaucoup que chaque fichier de test démarre une instance de serveur avec les paramètres appropriés, puis arrête cette instance lorsque les tests sont terminés. Cela signifie qu'il n'y a pas de dépendances étranges pour exécuter le test et que tout est propre. Cela signifie également que je peux faire des tests de démarrage / arrêt.

Alors, des conseils sur la façon de procéder? J'ai pensé à déclencher manuellement des exceptions pour les réduire, mais cela semble compliqué. J'ai fouillé dans la documentation et la source d'Express, mais je ne parviens pas à trouver une méthode qui arrêtera le serveur. Il peut également y avoir quelque chose dans socket.io pour cela, mais comme le serveur de socket est simplement connecté au serveur Express, je pense que cela doit se produire au niveau de la couche express.

dessiné
la source

Réponses:

156

Les choses ont changé car le serveur express n'hérite plus du serveur http du nœud. Heureusement, app.listen renvoie l'instance de serveur.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};
Rich Apodaca
la source
23
Dans le cas des tests Mocha, où vous avez besoin ('app'), je m'étend sur l'objet app: app.server = app.listen (3000); donc plus tard, je peux dire: var app = require ('./ app'); app.server.close ();
Jack Chi
2
lors du test du serveur, consultez github.com/visionmedia/supertest, il vous permettra de tester sans lancer le serveur réel
Lukas Liesis
Je vous suggère également de transmettre le rappel terminé à server.close()si vous appelez cela à partir d'un crochet.
Ullauri
Remarque: il existe une grande différence entre 'app', qui est l'instance de l'application Express, et la valeur de retour de 'app.listen', qui est l'instance de serveur HTTP native sous-jacente qui a la méthode 'close'. @JackChi a fait allusion à cela ci-dessus.
ajxs
Cela ne pose-t-il pas des problèmes avec les sockets client ouverts qui restent ouverts?
Cameron Tacklind
18

Utilisez app.close(). Exemple complet:

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

Appel app.close()à l'intérieur du rappel lorsque les tests sont terminés. Mais rappelez-vous que le processus est toujours en cours d'exécution (bien qu'il n'écoute plus).

Si après cela, vous devez terminer le processus, appelez process.exit(0).

Liens:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (il en va de même pour)

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

Srijan Choudhary
la source
1
Parfait, exactement ce que je cherchais. Je suppose que je ne l'ai pas trouvé dans Express parce qu'ils étendaient le serveur http du nœud principal, ce que je ne comprenais pas totalement. Merci!
drewww
Merci Srijan, cela m'a aidé aussi
Adam Hopkinson
Est-ce toujours vrai? express.createServer est marqué comme obsolète et donne une erreur indiquant que l'application n'hérite plus du serveur de http.js
Frank Schwieterman
4
Ce n'est pas valide depuis l'express 3.
gprasant
4
Exposer une URL pour fermer un serveur comme celui-ci n'est pas une bonne idée à mon humble avis.
shime le
2

J'ai répondu à plusieurs reprises à une variante de "comment terminer un serveur HTTP" sur différents canaux de soutien. Malheureusement, je ne peux recommander aucune des bibliothèques existantes car elles font défaut d'une manière ou d'une autre. J'ai depuis mis en place un package qui (je crois) gère tous les cas attendus d'une terminaison de serveur HTTP gracieuse.

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

Le principal avantage de http-terminator est que:

  • il ne modifie pas l'API Node.js
  • il détruit immédiatement toutes les sockets sans requête HTTP attachée
  • il permet un délai d'attente normal pour les sockets avec des requêtes HTTP en cours
  • il gère correctement les connexions HTTPS
  • il informe les connexions à l'aide de keep-alive que le serveur s'arrête en définissant une connexion: fermer l'en-tête
  • il ne met pas fin au processus Node.js

Utilisation avec 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
la source
0
//... some stuff 

var server = app.listen(3000);
server.close();
аlex dykyі
la source
-1

Vous pouvez facilement le faire en écrivant un script bash pour démarrer le serveur, exécuter les tests et arrêter le serveur. Cela a l'avantage de vous permettre de créer un alias sur ce script pour exécuter tous vos tests rapidement et facilement.

J'utilise de tels scripts pour tout mon processus de déploiement continu. Vous devriez regarder Dead Simple Git Workflow de Jon Rohan pour avoir un aperçu de cela.

Josh Smith
la source
2
Cela fonctionnerait, mais je préférerais une solution sans bash si possible. C'est peut-être une préférence stupide, mais j'aimerais démarrer / arrêter le serveur à partir du contexte de test car cela facilite l'écriture de tests spécifiques à la configuration du serveur + tests de démarrage / arrêt. De plus, cela n'introduit pas l'indirection d'avoir à exécuter des tests liés au serveur via un script séparé.
drewww
Pourquoi écrivez-vous des tests spécifiques à l'environnement? Peut-être que je me trompe, mais cela me semble être une mauvaise pratique. J'essaierais de rester indépendant de l'environnement avec vos tests, car vous voudriez que vos tests fonctionnent dans toute votre équipe, quel que soit leur environnement de développement.
Josh Smith
Je ne fais rien de spécifique à l'environnement ici, je ne pense pas. Il y aura une poignée d'options de démarrage différentes pour le serveur (comme la lecture des options de configuration à partir d'un fichier, l'état de chargement d'un magasin de données, etc.) qu'il serait bien de tester dans le même cadre que je teste tout le reste. J'aimerais également avoir des tests qui, par exemple, arrêtent le serveur, le ramènent à nouveau et m'assurent qu'il n'a pas perdu son état dans le processus. C'est plus facile si je peux le faire par programme à partir du nœud que d'avoir également du code de test dans bash.
drewww
Vous ne placeriez pas votre code de test dans bash lui-même. Il vous suffit de démarrer le serveur et d'exécuter les tests à partir du script, comme vous le feriez vous-même sur la ligne de commande. Il n'y a pas de vraie magie spéciale là-bas.
Josh Smith