Bagaimana cara saya secara terprogram mematikan sebuah instance ExpressJS untuk pengujian?

106

Saya mencoba mencari cara untuk menutup instance Express. Pada dasarnya, saya ingin kebalikan dari .listen(port)panggilan - bagaimana cara mendapatkan server Express untuk BERHENTI mendengarkan, melepaskan port, dan mematikan dengan bersih?

Saya tahu ini sepertinya pertanyaan yang aneh, jadi inilah konteksnya; mungkin ada cara lain untuk mendekati ini dan saya memikirkannya dengan cara yang salah. Saya mencoba menyiapkan kerangka pengujian untuk aplikasi socket.io/nodejs saya. Ini adalah aplikasi satu halaman, jadi dalam skrip pengujian saya (saya menggunakan Mocha, tetapi itu tidak terlalu penting) Saya ingin dapat memulai server, menjalankan pengujian terhadapnya, dan kemudian mematikan server. Saya bisa menyiasatinya dengan mengasumsikan bahwa server dihidupkan sebelum tes dimulai atau dengan salah satu tes memulai server dan setiap tes berikutnya menganggapnya sudah habis, tetapi itu benar-benar berantakan. Saya lebih suka jika setiap file pengujian memulai instance server dengan pengaturan yang sesuai dan kemudian menutup instance itu saat pengujian selesai. Itu berarti tidak ada ketergantungan yang aneh untuk menjalankan pengujian dan semuanya bersih. Ini juga berarti saya dapat melakukan pengujian startup / shutdown.

Jadi, ada saran tentang bagaimana melakukan ini? Saya telah memikirkan untuk memicu pengecualian secara manual untuk menurunkannya, tetapi itu tampaknya berantakan. Saya telah menggali dokumen dan sumber Express, tetapi sepertinya tidak dapat menemukan metode apa pun yang akan mematikan server. Mungkin juga ada sesuatu di socket.io untuk ini, tetapi karena server soket baru saja terpasang ke server Ekspres, saya pikir ini perlu terjadi di lapisan ekspres.

menggambarww
sumber

Jawaban:

156

Banyak hal telah berubah karena server ekspres tidak lagi mewarisi dari server http node. Untungnya, app.listen mengembalikan instance server.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};
Apodaca Kaya
sumber
23
Dalam kasus pengujian Mocha, di mana Anda memerlukan ('app') saya memperluas ke objek aplikasi: app.server = app.listen (3000); jadi nanti saya bisa bilang: var app = require ('./ app'); app.server.close ();
Jack Chi
2
saat menguji server, periksa github.com/visionmedia/supertest itu akan membiarkan Anda menguji tanpa meluncurkan server yang sebenarnya
Lukas Liesis
Saya juga menyarankan Anda meneruskan callback yang telah selesai ke server.close()jika memanggil ini dari dalam hook.
Ullauri
Catatan: Ada perbedaan besar antara 'app', yang merupakan instance Aplikasi Ekspres, dan nilai kembalian 'app.listen', yang merupakan instance HTTP Server asli yang mendasari yang memiliki metode 'tutup'. @JackChi mengisyaratkan hal ini di atas.
ajxs
Bukankah ini menyebabkan masalah dengan soket klien terbuka yang dibiarkan terbuka?
Cameron Tacklind
18

Gunakan app.close(). Contoh lengkap:

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

Panggil app.close()di dalam callback ketika tes telah berakhir. Namun perlu diingat bahwa prosesnya masih berjalan (meski sudah tidak mendengarkan lagi).

Jika setelah ini, Anda harus mengakhiri prosesnya, lalu panggil process.exit(0).

Tautan:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (berlaku sama untuk)

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

Srijan Choudhary
sumber
1
Sempurna, persis seperti yang saya cari. Saya kira saya tidak menemukannya di Express karena mereka memperluas server http node inti, yang saya tidak sepenuhnya mengerti. Terima kasih!
menggambarww
Terima kasih Srijan, itu membantu saya juga
Adam Hopkinson
Apakah ini masih benar? express.createServer ditandai sebagai usang, dan memberikan kesalahan yang mengatakan aplikasi tidak lagi mewarisi dari server
http.js
4
Ini tidak berlaku sejak ekspres 3.
gprasant
4
Mengekspos URL untuk menutup server seperti ini bukanlah ide yang baik IMHO.
tayang
2

Saya telah menjawab variasi "cara menghentikan server HTTP" berkali-kali dengan cara yang berbeda saluran dukungan. Sayangnya, saya tidak dapat merekomendasikan salah satu pustaka yang ada karena mereka kurang dalam satu atau lain cara. Saya telah mengumpulkan paket yang (saya percaya) menangani semua kasus yang diharapkan dari penghentian server HTTP yang anggun.

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

Manfaat utama http-terminator adalah:

  • itu bukan API Node.js monkey-patch
  • itu segera menghancurkan semua soket tanpa permintaan HTTP terlampir
  • itu memungkinkan batas waktu yang anggun ke soket dengan permintaan HTTP yang sedang berlangsung
  • itu menangani koneksi HTTPS dengan benar
  • itu menginformasikan koneksi menggunakan keep-hidup bahwa server dimatikan dengan mengatur koneksi: tutup header
  • itu tidak menghentikan proses Node.js

Penggunaan dengan 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
sumber
0
//... some stuff 

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

Anda dapat dengan mudah melakukan ini dengan menulis skrip bash untuk memulai server, menjalankan pengujian, dan menghentikan server. Ini memiliki keuntungan karena memungkinkan Anda membuat alias ke skrip tersebut untuk menjalankan semua pengujian Anda dengan cepat dan mudah.

Saya menggunakan skrip tersebut untuk seluruh proses penerapan berkelanjutan saya. Anda harus melihat Alur Kerja Git Sederhana Mati Jon Rohan untuk beberapa wawasan tentang ini.

Josh Smith
sumber
2
Ini akan berhasil, tetapi saya lebih suka solusi bebas bash jika memungkinkan. Mungkin ini adalah preferensi yang bodoh, tetapi saya ingin memulai / menghentikan server dari konteks pengujian karena ini mempermudah penulisan pengujian khusus server-config + pengujian startup / shutdown. Plus, itu tidak memperkenalkan tipu muslihat harus menjalankan tes terkait server melalui skrip terpisah.
menggambar www
Mengapa Anda menulis tes khusus lingkungan? Mungkin saya salah, tapi ini bagi saya sebagai praktik yang buruk. Saya akan mencoba untuk menjaga lingkungan agnostik dengan pengujian Anda, karena Anda ingin pengujian Anda bekerja di seluruh tim Anda terlepas dari lingkungan pengembangan mereka.
Josh Smith
Saya tidak melakukan apa pun yang khusus untuk lingkungan di sini, saya tidak berpikir. Akan ada beberapa opsi startup yang berbeda untuk server (seperti membaca opsi konfigurasi dari file, memuat status dari datastore, dll) yang akan menyenangkan untuk menguji dalam kerangka yang sama saya menguji yang lainnya. Saya juga ingin melakukan tes yang, misalnya, mematikan server, mengaktifkannya kembali, dan memastikan tidak kehilangan status dalam prosesnya. Itu lebih mudah jika saya bisa melakukannya secara terprogram dari node daripada memiliki kode pengujian di bash juga.
menggambarww
Anda tidak akan menempatkan kode pengujian Anda di bash itu sendiri. Anda cukup memulai server dan menjalankan tes dari skrip, seperti yang Anda lakukan sendiri pada baris perintah. Tidak ada keajaiban khusus yang nyata di sana.
Josh Smith