¿Cómo cierro programáticamente una instancia de ExpressJS para realizar pruebas?

106

Estoy tratando de averiguar cómo cerrar una instancia de Express. Básicamente, quiero lo contrario de la .listen(port)llamada: ¿cómo hago para que un servidor Express DEJE de escuchar, libere el puerto y se apague limpiamente?

Sé que parece que puede ser una consulta extraña, así que aquí está el contexto; tal vez haya otra forma de abordar esto y lo estoy pensando de manera incorrecta. Estoy intentando configurar un marco de prueba para mi aplicación socket.io/nodejs. Es una aplicación de una sola página, así que en mis scripts de prueba (estoy usando Mocha, pero eso realmente no importa) Quiero poder iniciar el servidor, ejecutar pruebas en él y luego apagar el servidor. Puedo solucionar esto asumiendo que el servidor está encendido antes de que comience la prueba o haciendo que una de las pruebas inicie el servidor y que cada prueba posterior asuma que está funcionando, pero eso es realmente complicado. Preferiría que cada archivo de prueba inicie una instancia de servidor con la configuración adecuada y luego cierre esa instancia cuando terminen las pruebas. Eso significa que no hay dependencias extrañas para ejecutar la prueba y todo está limpio. También significa que puedo hacer pruebas de inicio / apagado.

Entonces, ¿algún consejo sobre cómo hacer esto? He pensado en activar excepciones manualmente para eliminarlo, pero eso parece complicado. He revisado los documentos y la fuente de Express, pero parece que no puedo encontrar ningún método que apague el servidor. También podría haber algo en socket.io para esto, pero dado que el servidor de socket está conectado al servidor Express, creo que esto debe suceder en la capa express.

dibujóww
fuente

Respuestas:

156

Las cosas han cambiado porque el servidor express ya no hereda del servidor http del nodo. Afortunadamente, app.listen devuelve la instancia del servidor.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};
Rico Apodaca
fuente
23
En el caso de las pruebas de Mocha, donde necesita ('aplicación'), extiendo al objeto de la aplicación: app.server = app.listen (3000); luego puedo decir: var app = require ('./ app'); app.server.close ();
Jack Chi
2
cuando pruebe el servidor, visite github.com/visionmedia/supertest , le permitirá probar sin iniciar el servidor real
Lukas Liesis
También le sugiero que pase la devolución de llamada realizada a server.close()si llama a esto desde un gancho.
Ullauri
Nota: Existe una gran diferencia entre 'app', que es la instancia de Express Application, y el valor de retorno de 'app.listen', que es la instancia del servidor HTTP nativo subyacente que tiene el método 'close'. @JackChi insinuó esto arriba.
ajxs
¿No causa esto problemas con los sockets de cliente abiertos que se dejan abiertos?
Cameron Tacklind
18

Utilice app.close(). Ejemplo completo:

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

Llame app.close()dentro de la devolución de llamada cuando las pruebas hayan terminado. Pero recuerde que el proceso aún se está ejecutando (aunque ya no se escucha).

Si después de esto, necesita finalizar el proceso, llame process.exit(0).

Enlaces:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (se aplica lo mismo)

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

Srijan Choudhary
fuente
1
Perfecto, exactamente lo que estaba buscando. Supongo que no lo encontré en Express porque estaban extendiendo el servidor http del nodo central, que no entendí totalmente. ¡Gracias!
dibujó el
Gracias Srijan, eso también me ayudó
Adam Hopkinson
¿Sigue siendo cierto esto? express.createServer está marcado como obsoleto y da un error que dice que la aplicación ya no hereda del servidor
http.js
4
Esto no es válido desde Express 3.
gprasant
4
Exponer una URL para cerrar un servidor como este no es una buena idea en mi humilde opinión.
shime
2

He respondido una variación de "cómo terminar un servidor HTTP" muchas veces en diferentes canales de apoyo. Desafortunadamente, no pude recomendar ninguna de las bibliotecas existentes porque faltan de una manera u otra. Desde entonces, he creado un paquete que (creo) está manejando todos los casos que se esperan de una terminación elegante del servidor HTTP.

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

El principal beneficio de http-terminator es que:

  • no aplica un parche a la API de Node.js
  • inmediatamente destruye todos los sockets sin una solicitud HTTP adjunta
  • permite un tiempo de espera elegante para los sockets con solicitudes HTTP en curso
  • maneja correctamente las conexiones HTTPS
  • informa a las conexiones mediante Keep-Alive que el servidor se está cerrando estableciendo una conexión: cerrar encabezado
  • no finaliza el proceso de Node.js

Uso con 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
fuente
0
//... some stuff 

var server = app.listen(3000);
server.close();
Alex dykyі
fuente
-1

Puede hacer esto fácilmente escribiendo un script bash para iniciar el servidor, ejecutar las pruebas y detener el servidor. Esto tiene la ventaja de permitirle asignar un alias a ese script para ejecutar todas sus pruebas rápida y fácilmente.

Utilizo estos scripts para todo mi proceso de implementación continua. Debería consultar el flujo de trabajo Dead Simple Git de Jon Rohan para obtener información sobre esto.

Josh Smith
fuente
2
Esto funcionaría, pero preferiría una solución sin bash si es posible. Tal vez sea una preferencia estúpida, pero me gustaría iniciar / detener el servidor desde el contexto de prueba porque facilita la escritura de pruebas específicas de configuración del servidor + pruebas de inicio / apagado. Además, no introduce la indirecta de tener que ejecutar pruebas relacionadas con el servidor a través de un script separado.
dibujóww
¿Por qué está escribiendo pruebas específicas del entorno? Tal vez me equivoque, pero esto me parece una mala práctica. Intentaría ser independiente del entorno con sus pruebas, ya que querría que sus pruebas funcionen en todo su equipo, independientemente de su entorno de desarrollo.
Josh Smith
No estoy haciendo nada específico del entorno aquí, no creo. Habrá un puñado de opciones de inicio diferentes para el servidor (como leer las opciones de configuración de un archivo, estado de carga de un almacén de datos, etc.) que sería bueno probar en el mismo marco que pruebo todo lo demás. También me gustaría tener pruebas que, por ejemplo, apaguen el servidor, lo vuelvan a activar y se aseguren de que no perdió el estado en el proceso. Eso es más fácil si puedo hacerlo programáticamente desde el nodo que tener código de prueba en bash también.
dibujó el
No colocaría su código de prueba en bash. Simplemente iniciaría el servidor y ejecutaría las pruebas desde el script, tal como lo haría usted mismo en la línea de comandos. Allí no hay magia especial real.
Josh Smith