449 Stimmen

Führen einer Bereinigungsaktion kurz bevor Node.js beendet wird

Ich möchte Node.js sagen, dass es immer etwas tun soll, kurz bevor es beendet wird, aus welchem Grund auch immer — Strg+C, eine Ausnahme oder aus einem anderen Grund.

Ich habe dies versucht:

process.on('exit', function (){
    console.log('Auf Wiedersehen!');
});

Ich habe den Prozess gestartet, ihn beendet und es ist nichts passiert. Ich habe ihn erneut gestartet, Strg+C gedrückt und es passierte immer noch nichts...

1 Stimmen

689voto

Emil Condrea Punkte 9429

AKTUALISIERUNG:

Sie können einen Handler für `process.on('exit')` registrieren und in jedem anderen Fall (`SIGINT` oder unbehandelte Ausnahme) `process.exit()` aufrufen

process.stdin.resume(); // damit das Programm nicht sofort geschlossen wird

function exitHandler(options, exitCode) {
    if (options.cleanup) console.log('sauber');
    if (exitCode || exitCode === 0) console.log(exitCode);
    if (options.exit) process.exit();
}

// etwas tun, wenn die App geschlossen wird
process.on('exit', exitHandler.bind(null,{cleanup:true}));

// fängt das Strg+C-Ereignis ab
process.on('SIGINT', exitHandler.bind(null, {exit:true}));

// fängt das "kill pid" Ereignis ab (zum Beispiel: Nodemon Neustart)
process.on('SIGUSR1', exitHandler.bind(null, {exit:true}));
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));

// fängt unbehandelte Ausnahmen ab
process.on('uncaughtException', exitHandler.bind(null, {exit:true}));

Dies funktioniert nur, wenn Sie synchronen Code im Handler aufrufen, sonst wird der Handler unendlich aufgerufen

6 Stimmen

Gibt es einen Weg, sowohl Ctrl + C als auch einen normalen Exit am selben Ort zu handhaben, oder muss ich zwei separate Handler schreiben? Was ist mit anderen Arten von Exits, wie eine unbehandelte Ausnahme - gibt es einen speziellen Handler für diesen Fall, aber sollte ich dies mit einer dritten Kopie des gleichen Handlers behandeln?

0 Stimmen

Auf Linux funktioniert es mit dem SIGINT-Ereignis, sodass Sie tatsächlich die CTRL+C-Aktion abfangen können, aber die Windows-Version von Node.js hat keine direkte Unterstützung dafür. Für unbehandelte Ausnahmen können Sie diese mit : nodejs.org/api/process.html#process_event_uncaughtexception abfangen.

1 Stimmen

@RobFox resume() initialisiert den Lesevorgang. Stdin ist standardmäßig pausiert. Weitere Informationen finden Sie unter: github.com/joyent/node/blob/…

206voto

CanyonCasa Punkte 2041

Der unten stehende Skript erlaubt es, einen einzelnen Handler für alle Beendigungsbedingungen zu haben. Es verwendet eine app-spezifische Callback-Funktion, um benutzerdefinierten Aufräumcode auszuführen.

cleanup.js

// Objekt zum Erfassen von Prozessbeendigungen und zum Aufruf von app-spezifischen Aufräumfunktionen

function noOp() {};

exports.Cleanup = function Cleanup(callback) {

  // Nutzer-Callback an das Prozessereignisemitter anhängen
  // wenn kein Callback vorhanden ist, wird es dennoch ordnungsgemäß bei Strg+C beendet
  callback = callback || noOp;
  process.on('cleanup',callback);

  // App-spezifische Bereinigung vor dem Beenden durchführen
  process.on('exit', function () {
    process.emit('cleanup');
  });

  // Strg+C-Ereignis abfangen und normal beenden
  process.on('SIGINT', function () {
    console.log('Strg+C...');
    process.exit(2);
  });

  // Unbehandelte Ausnahmen abfangen, verfolgen und dann normal beenden
  process.on('uncaughtException', function(e) {
    console.log('Unbehandelte Ausnahme...');
    console.log(e.stack);
    process.exit(99);
  });
};

Dieser Code erfasst unbehandelte Ausnahmen, Strg+C- und normale Beendigungsvorgänge. Er ruft dann eine einzelne optionale Benutzerbereinigungsrückruffunktion auf, bevor er beendet wird, und behandelt alle Beendigungsbedingungen mit einem einzigen Objekt.

Das Modul erweitert einfach das process-Objekt anstelle eines anderen Ereignisemitters zu definieren. Ohne eine app-spezifische Callback-Funktion wird die Bereinigung auf eine No-Op-Funktion zurückgesetzt. Dies war für meinen Gebrauch ausreichend, wo Kindprozesse ausgeführt wurden, wenn durch Strg+C beendet wurde.

Sie können problemlos weitere Beendeereignisse wie SIGHUP hinzufügen, wenn gewünscht. Hinweis: Gemäß dem NodeJS-Handbuch kann SIGKILL keinen Listener haben. Der unten stehende Testcode zeigt verschiedene Möglichkeiten der Verwendung von cleanup.js

// Test cleanup.js auf Version 0.10.21

// Lädt das Modul und registriert die app-spezifische Bereinigungsrückrufroutine...
var cleanup = require('./cleanup').Cleanup(myCleanup);
//var cleanup = require('./cleanup').Cleanup(); // wird noOp aufrufen

// Definiert eine app-spezifische Callback-Funktion...
function myCleanup() {
  console.log('App-spezifischer Bereinigungscode...');
};

// Der folgende Code wird nur für den Testdemo benötigt

// Verhindert, dass das Programm sofort geschlossen wird
process.stdin.resume();

// Löst eine unbehandelte Ausnahme aus, wenn aufgerufen, da das Modul nicht existiert
function error() {
  console.log('Fehler');
  var x = require('');
};

// Probieren Sie jeweils das Folgende nacheinander aus:

// Kommentieren Sie die nächste Zeile aus, um das Beenden bei einer unbehandelten Ausnahme zu testen
//setTimeout(error,2000);

// Kommentieren Sie die nächste Zeile aus, um das normale Beenden zu testen
//setTimeout(function(){process.exit(3)}, 2000);

// Geben Sie Strg+C ein, um das erzwungene Beenden zu testen

0 Stimmen

@Pier-LucGendreau Wohin gehört dieser spezifische Code?

18 Stimmen

I habe diesen Code unverzichtbar gefunden und ein Node-Paket dafür erstellt, mit Anpassungen, unter Nennung Ihres Namens und dieser SO-Antwort. Ich hoffe, das ist in Ordnung, @CanyonCasa. Vielen Dank! npmjs.com/package/node-cleanup

4 Stimmen

Ich liebe das Bereinigen. Aber ich mag den process.exit(0); nicht cons.org/cracauer/sigint.html Meine Meinung ist, dass du den Kernel das Beenden übernehmen lassen solltest. Du beendest nicht auf die gleiche Weise wie bei einem SIGINT. SIGINT beendet nicht mit 2. Du verwechselst das SIGINT mit einem Fehlercode. Sie sind nicht dasselbe. Tatsächlich beendet Ctrl+C mit 130. Nicht mit 2. tldp.org/LDP/abs/html/exitcodes.html

84voto

light24bulbs Punkte 2545

Dies erfasst jedes Exit-Ereignis, das ich finden kann und das behandelt werden kann. Bisher scheint es ziemlich zuverlässig und sauber zu sein.

[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`].forEach((eventType) => {
  process.on(eventType, cleanUpServer.bind(null, eventType));
})

3 Stimmen

Das ist großartig!

1 Stimmen

Tolle Arbeit, ich benutze sie gerade in der Produktion! Vielen Dank!

0 Stimmen

Es wäre schön, einige Informationen zu diesem Ereignis zu erhalten oder einen Link zu Ressourcen.

24voto

user1278519 Punkte 826

"exit" ist ein Ereignis, das ausgelöst wird, wenn ein Knoten seinen event loop intern beendet, es wird nicht ausgelöst, wenn Sie den Prozess extern beenden.

Was Sie suchen, ist das Ausführen von etwas bei einem SIGINT.

Die Dokumente unter http://nodejs.org/api/process.html#process_signal_events geben ein Beispiel:

Beispiel für das Hören auf SIGINT:

// Beginnen Sie mit dem Lesen von stdin, damit wir nicht beenden.
process.stdin.resume();

process.on('SIGINT', function () {
  console.log('Got SIGINT.  Drücken Sie Strg-D, um zu beenden.');
});

Hinweis: Dies scheint den SIGINT zu unterbrechen, und Sie müssten process.exit() aufrufen, wenn Sie mit Ihrem Code fertig sind.

2 Stimmen

Gibt es eine Möglichkeit, sowohl Ctrl+C als auch ein normales Beenden an einem Ort zu behandeln? Oder muss ich zwei identische Handler schreiben?

0 Stimmen

Nur als Hinweis: Wenn Sie einen Knoten beenden müssen, indem Sie `kill -2` ausführen, wird der `SIGINT`-Code übergeben. Wir müssen es auf diese Weise tun, weil wir das Node-Protokollieren in eine TXT-Datei haben, sodass Strg + C nicht möglich ist.

13voto

Abdullah Punkte 919
function fnAsyncTest(callback) {
    require('fs').writeFile('async.txt', 'bye!', callback);
}

function fnSyncTest() {
    for (var i = 0; i < 10; i++) {}
}

function killProcess() {

    if (process.exitTimeoutId) {
        return;
    }

    process.exitTimeoutId = setTimeout(() => process.exit, 5000);
    console.log('process will exit in 5 seconds');

    fnAsyncTest(function() {
        console.log('async op. done', arguments);
    });

    if (!fnSyncTest()) {
        console.log('sync op. done');
    }
}

// https://nodejs.org/api/process.html#process_signal_events
process.on('SIGTERM', killProcess);
process.on('SIGINT', killProcess);

process.on('uncaughtException', function(e) {

    console.log('[uncaughtException] app will be terminated: ', e.stack);

    killProcess();
    /**
     * @https://nodejs.org/api/process.html#process_event_uncaughtexception
     *  
     * 'uncaughtException' should be used to perform synchronous cleanup before shutting down the process. 
     * It is not safe to resume normal operation after 'uncaughtException'. 
     * If you do use it, restart your application after every unhandled exception!
     * 
     * You have been warned.
     */
});

console.log('App is running...');
console.log('Try to press CTRL+C or SIGNAL the process with PID: ', process.pid);

process.stdin.resume();
// just for testing

7 Stimmen

Dieses Antwort verdient all den Ruhm, aber weil es keine Erklärung gibt, gibt es leider auch kein Up-Vote. Was signifikant an dieser Antwort ist, sagt die Dokumentation: "Listener-Funktionen dürfen nur synchrone Operationen ausführen. Der Node.js-Prozess wird sofort nach Aufrufen der 'exit'-Event-Listener beendet, wodurch alle zusätzlichen Arbeiten, die sich noch in der Ereignisschleife befinden, abgebrochen werden. ", und diese Antwort überwindet diese Einschränkung!

0 Stimmen

Wenn ich das richtig lese, wird das Beenden immer eine feste Zeit dauern (fünf Sekunden), was möglicherweise zu lang oder schlimmer noch zu kurz ist, wenn der asynchrone Vorgang mehr Zeit benötigt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X