2013-01-17 14 views
14

Potrzebuję zrobić kilka przydatnych rzeczy, gdy moja usługa Express.js została zatrzymana przez SIGINT. Korzystanie Express.js wersję 3.0.6, rozumiem, że to powinno działać:Jak poprawnie obsłużyć SIGINT za pomocą Express.js?

var express = require('express'); 

var app = express(); 
var server = app.listen(3000); 

process.on('SIGINT', function() { 
    console.log('Do something useful here.'); 
    server.close(); 
}); 

Ale proces nie daje mi monit bash chyba wydać SIGINT (Kontrola - C) dwa razy:

$ node problem.js 
^CDo something useful here. 
^CDo something useful here. 

net.js:1046 
    throw new Error('Not running'); 
     ^
Error: Not running 
    at Server.close (net.js:1046:11) 
    at process.<anonymous> (/path/to/problem.js:8:10) 
    at process.EventEmitter.emit (events.js:93:17) 
    at SignalWatcher.startup.processSignalHandlers.process.on.process.addListener.w.callback (node.js:486:45) 
$ 

Jeszcze jedno zastrzeżenie. Jeśli uruchomię tę usługę Express.js i nie wyślę żadnych żądań, wtedy SIGINT zakończy się poprawnie.

Najwyraźniej jest coś fundamentalnego, czego tu brakuje?

Odpowiedz

21

Złapanie obsługi SIGINT uniemożliwia zachowanie domyślne , czyli zamknięcie procesu. Gdy użyjesz Ctrl+C po raz drugi, proces zginie, ponieważ server.close zgłasza nieprzechwycony wyjątek.

Po prostu dodaj końcówkę process.exit() do końca swojej obsługi SIGINT, aby zakończyć proces z wdziękiem.

+0

Korzystanie 'process.exit()' jest jak wysyłanie^C po zrobił jedną rzecz i nie powinny być traktowane z wdziękiem (imho). Myślę, że bardziej kompletna odpowiedź jest poniżej (choć trochę spóźniona). – Whyhankee

4

Używam tego wariantu:

server.close(() => { 
    process.exit(0) 
}) 
5

wskrzesza Stare, ponieważ kwestia ta nie jest całkowicie (lub poprawnie) odpowiedział i ludzie mogą jeszcze znaleźć tę odpowiedź.

Ważną częścią pytanie brzmi:

Jeszcze jeden wyjątek. Jeśli uruchomię tę usługę Express.js i nie wyślę żadnych żądań, SIGINT zakończy się poprawnie. Najwyraźniej jest coś fundamentalnego, czego mi tutaj brakuje? `

To, czego brakuje, to domyślne zachowanie połączeń otwartych (utrzymywanie aktywności HTTP) do ponownego użycia. Tak więc, gdy pojawiło się (ostatnie) żądanie, wciąż coś jest w pętli zdarzeń i to jest powodem, dla którego twoja aplikacja się nie zamyka.

Używając process.exit() będzie działać, ale jest jak wysyłanie kolejnej^C i może ukryć fakt, że wciąż jest coś innego otwartego (np. Połączenia z bazą danych). Twoja aplikacja powinna się zamknąć, gdy nie ma już nic w pętli zdarzeń.

Tak więc, zmodyfikowałem twój przykład, ustawiając 5 sekund na podtrzymanie połączenia, aby mógł on w rozsądnym czasie zakończyć się płynnie.

var express = require('express'); 
 

 
var serverPort = 3000; 
 
var app = express(); 
 
var server = app.listen(serverPort); 
 

 

 
// HTTP Keep-Alive to a short time to allow graceful shutdown 
 
server.on('connection', function (socket) { 
 
    socket.setTimeout(5 * 1000); 
 
}); 
 

 
// Handle ^C 
 
process.on('SIGINT', shutdown); 
 

 
// Do graceful shutdown 
 
function shutdown() { 
 
    console.log('graceful shutdown express'); 
 
    server.close(function() { 
 
    console.log('closed express'); 
 
    }); 
 
} 
 

 
console.log('running server: http://localhost:' + serverPort);

+1

Ze względu na duże potencjalne opóźnienie przed zamknięciem, może to nadal nie być idealne, i sprawia, że ​​utrzymujące się połączenia są potencjalnie mniej przydatne. Aby uzyskać pełniejsze rozwiązanie, może być sensowne przejście do modułu wdzięcznego wyjścia: https://www.npmjs.com/package/express-graceful-exit.Moduł ten zamknie utrzymujące się połączenia i zaczeka, aż inne aktywności zakończą się przed wyjściem. – nneonneo