Выполнение действий очистки непосредственно перед node.js завершает

Я хочу сказать node.js всегда делать что-то непосредственно перед тем, как оно выйдет, по любой причине - Ctrl + C, исключение или по любой другой причине.

Я пробовал это:

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

Начал процесс, убил его, и ничего не произошло; снова начал, нажал Ctrl + C, и до сих пор ничего не произошло...

Ответ 1

UPDATE:

Вы можете зарегистрировать обработчик для process.on('exit') и в любом другом случае (SIGINT или необработанное исключение) для вызова process.exit()

process.stdin.resume();//so the program will not close instantly

function exitHandler(options, err) {
    if (options.cleanup) console.log('clean');
    if (err) console.log(err.stack);
    if (options.exit) process.exit();
}

//do something when app is closing
process.on('exit', exitHandler.bind(null,{cleanup:true}));

//catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {exit:true}));

// catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR1', exitHandler.bind(null, {exit:true}));
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));

//catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {exit:true}));

Ответ 2

Ниже приведено script, позволяющее иметь один обработчик для всех условий выхода. Для выполнения пользовательского кода очистки используется специальная функция обратного вызова приложения.

cleanup.js

// Object to capture process exits and call app specific cleanup function

function noOp() {};

exports.Cleanup = function Cleanup(callback) {

  // attach user callback to the process event emitter
  // if no callback, it will still exit gracefully on Ctrl-C
  callback = callback || noOp;
  process.on('cleanup',callback);

  // do app specific cleaning before exiting
  process.on('exit', function () {
    process.emit('cleanup');
  });

  // catch ctrl+c event and exit normally
  process.on('SIGINT', function () {
    console.log('Ctrl-C...');
    process.exit(2);
  });

  //catch uncaught exceptions, trace, then exit normally
  process.on('uncaughtException', function(e) {
    console.log('Uncaught Exception...');
    console.log(e.stack);
    process.exit(99);
  });
};

Этот код перехватывает неперехваченные исключения, Ctrl-C и обычные события выхода. Затем он вызывает одну дополнительную функцию обратного вызова очистки пользователя перед выходом, обрабатывая все условия выхода с помощью одного объекта.

Модуль просто расширяет объект процесса, а не определяет другой эмитент событий. Без специального обратного вызова приложения очистка по умолчанию не имеет функции op. Этого было достаточно для моего использования, когда дочерние процессы оставались включенными при выходе из Ctrl-C.

Вы можете легко добавить другие события выхода, такие как SIGHUP, по желанию. Примечание: в руководстве NodeJS SIGKILL не может иметь слушателя. В приведенном ниже тестовом коде показаны различные способы использования cleanup.js

// test cleanup.js on version 0.10.21

// loads module and registers app specific cleanup callback...
var cleanup = require('./cleanup').Cleanup(myCleanup);
//var cleanup = require('./cleanup').Cleanup(); // will call noOp

// defines app specific callback...
function myCleanup() {
  console.log('App specific cleanup code...');
};

// All of the following code is only needed for test demo

// Prevents the program from closing instantly
process.stdin.resume();

// Emits an uncaught exception when called because module does not exist
function error() {
  console.log('error');
  var x = require('');
};

// Try each of the following one at a time:

// Uncomment the next line to test exiting on an uncaught exception
//setTimeout(error,2000);

// Uncomment the next line to test exiting normally
//setTimeout(function(){process.exit(3)}, 2000);

// Type Ctrl-C to test forced exit 

Ответ 3

"exit" - событие, которое запускается, когда node завершает цикл событий внутри, он не запускается, когда вы завершаете процесс извне.

То, что вы ищете, выполняет что-то на SIGINT.

Документы в http://nodejs.org/api/process.html#process_signal_events приводят пример:

Пример прослушивания SIGINT:

// Start reading from stdin so we don't exit.
process.stdin.resume();

process.on('SIGINT', function () {
  console.log('Got SIGINT.  Press Control-D to exit.');
});

Примечание: это, по-видимому, прерывает сигмин, и вам нужно будет вызвать process.exit(), когда вы закончите свой код.

Ответ 4

Просто хотел упомянуть пакет death здесь: https://github.com/jprichardson/node-death

Пример:

var ON_DEATH = require('death')({uncaughtException: true}); //this is intentionally ugly

ON_DEATH(function(signal, err) {
  //clean up code here
})

Ответ 5

io.js имеет exit и a beforeExit, которые делают то, что вы хотите.

Ответ 6

var fs = require('fs');

function async(callback) {
    fs.writeFile('async.txt', 'bye!', callback);
}

function sync()
{
    for (var i = 0; i < 10; i++) {}
    return true;
}

function killProcess()
{
    if (process.exitTimeoutId){
        return;
    }

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

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

    if (sync()) {
        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

В случае, когда процесс был порожден другим процессом node, например:

var child = spawn('gulp', ['watch'], {
    stdio: 'inherit',
});

И вы попытаетесь убить его позже, используя:

child.kill();

Вот как вы обрабатываете событие [у ребенка]:

process.on('SIGTERM', function() {
    console.log('Goodbye!');
});