Como encerro programaticamente uma instância do ExpressJS para teste?

106

Estou tentando descobrir como encerrar uma instância do Express. Basicamente, quero o inverso da .listen(port)chamada - como faço para que um servidor Express PARE de escutar, libere a porta e desligue de forma limpa?

Eu sei que parece ser uma consulta estranha, então aqui está o contexto; talvez haja outra maneira de abordar isso e eu esteja pensando da maneira errada. Estou tentando configurar uma estrutura de teste para meu aplicativo socket.io/nodejs. É um aplicativo de página única, então em meus scripts de teste (estou usando o Mocha, mas isso realmente não importa) Eu quero ser capaz de iniciar o servidor, executar testes nele e, em seguida, desligar o servidor. Posso contornar isso presumindo que o servidor esteja ligado antes do início do teste ou fazendo com que um dos testes inicie o servidor e todos os testes subsequentes presumam que ele está ativo, mas isso é realmente confuso. Eu preferiria que cada arquivo de teste iniciasse uma instância do servidor com as configurações apropriadas e, em seguida, desligasse essa instância quando os testes terminassem. Isso significa que não há dependências estranhas para executar o teste e tudo está limpo. Também significa que posso fazer testes de inicialização / desligamento.

Então, algum conselho sobre como fazer isso? Pensei em disparar exceções manualmente para derrubá-lo, mas isso parece confuso. Procurei nos documentos e na origem do Express, mas não consigo encontrar nenhum método que desligue o servidor. Também pode haver algo no socket.io para isso, mas como o servidor de soquete está apenas conectado ao servidor Express, acho que isso precisa acontecer na camada expressa.

desenhouww
fonte

Respostas:

156

As coisas mudaram porque o servidor expresso não herda mais do servidor http do nó. Felizmente, app.listen retorna a instância do servidor.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};
Rich Apodaca
fonte
23
No caso do teste Mocha, onde você requer ('app') eu estendo para o objeto app: app.server = app.listen (3000); então, mais tarde, posso dizer: var app = require ('./ app'); app.server.close ();
Jack Chi
2
ao testar o servidor, verifique github.com/visionmedia/supertest; ele permitirá que você teste sem iniciar o servidor real
Lukas Liesis
Também sugiro que você passe o retorno de chamada concluído para server.close()se estiver chamando de dentro de um gancho.
Ullauri
Nota: Há uma grande diferença entre 'app', que é a instância Express Application, e o valor de retorno de 'app.listen', que é a instância do servidor HTTP nativo subjacente que tem o método 'close'. @JackChi sugeriu isso acima.
ajxs
Isso não causa problemas com sockets de cliente abertos que são deixados abertos?
Cameron Tacklind
18

Use app.close(). Exemplo 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);

Chame app.close()dentro do retorno de chamada quando os testes terminarem. Mas lembre-se de que o processo ainda está em execução (embora não esteja mais ouvindo).

Se depois disso você precisar encerrar o processo, ligue process.exit(0).

Links:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (o mesmo se aplica a)

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

Srijan Choudhary
fonte
1
Perfeito, exatamente o que eu estava procurando. Acho que não encontrei no Express porque eles estavam estendendo o servidor http do nó principal, o que eu não entendi totalmente. Obrigado!
desenhou em
Obrigado Srijan, isso me ajudou também
Adam Hopkinson
Isso ainda é verdade? express.createServer é marcado como obsoleto e apresenta um erro dizendo que o aplicativo não herda mais do servidor
http.js
4
Isso não é válido porque expresso 3.
gprasant
4
Expor uma URL para fechar um servidor como este não é uma boa ideia IMHO.
shime
2

Eu respondi uma variação de "como encerrar um servidor HTTP" muitas vezes em diferentes canais de suporte. Infelizmente, eu não poderia recomendar nenhuma das bibliotecas existentes porque elas estão faltando de uma ou outra forma. Desde então, reuni um pacote que (acredito) está lidando com todos os casos esperados de encerramento normal do servidor HTTP.

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

O principal benefício do http-terminator é que:

  • não faz monkey-patch na API Node.js
  • ele destrói imediatamente todos os sockets sem uma solicitação HTTP anexada
  • permite tempo limite normal para sockets com solicitações HTTP em andamento
  • lida adequadamente com conexões HTTPS
  • ele informa as conexões usando o keep-alive que o servidor está sendo encerrado, definindo um connection: close header
  • não encerra o processo Node.js.

Uso com 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
fonte
0
//... some stuff 

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

Você pode fazer isso facilmente escrevendo um script bash para iniciar o servidor, executar os testes e parar o servidor. Isso tem a vantagem de permitir que você crie um alias para esse script para executar todos os seus testes de forma rápida e fácil.

Eu uso esses scripts em todo o meu processo de implantação contínua. Você deve examinar o fluxo de trabalho Dead Simple Git de Jon Rohan para obter alguns insights sobre isso.

Josh Smith
fonte
2
Isso funcionaria, mas eu prefiro uma solução sem bash, se possível. Talvez seja uma preferência estúpida, mas eu gostaria de iniciar / parar o servidor do contexto de teste porque torna mais fácil escrever testes específicos de configuração de servidor + testes de inicialização / desligamento. Além disso, não introduz o engano de ter que executar testes relacionados ao servidor por meio de um script separado.
desenhou em
Por que você está escrevendo testes específicos do ambiente? Talvez eu esteja errado, mas isso me parece uma prática ruim. Eu tentaria manter o ambiente independente de seus testes, pois você gostaria que seus testes funcionassem em sua equipe, independentemente do ambiente de desenvolvimento.
Josh Smith
Não estou fazendo nada específico do ambiente aqui, não acho. Haverá um punhado de opções de inicialização diferentes para o servidor (como ler opções de configuração de um arquivo, carregar o estado de um armazenamento de dados, etc) que seria bom testar na mesma estrutura que eu testo todo o resto. Eu também gostaria de ter testes que, por exemplo, desliguem o servidor, liguem-no novamente e garantam que ele não perca o estado no processo. Isso é mais fácil se eu puder fazer isso programaticamente a partir do nó do que ter o código de teste no bash também.
desenhou em
Você não colocaria seu código de teste no próprio bash. Você simplesmente inicializaria o servidor e executaria os testes do script, da mesma forma que faria na linha de comando. Não há nenhuma mágica especial real lá.
Josh Smith