Как выполнить операцию async при выходе

Я пытаюсь выполнить асинхронную операцию до завершения моего процесса.

Выражение "завершено" Я имею в виду каждую возможность прекращения:

  • ctrl+c
  • Неотключенное исключение
  • Сбои
  • Конец кода
  • Все..

Насколько мне известно, событие exit делает это, но для синхронных операций.

Чтение документов Nodejs я обнаружил beforeExit событие для асинхронных операций BUT:

Событие 'beforeExit' не выдается для условий, вызывающих явное завершение, таких как вызов process.exit() или неотображаемые исключения.

"beforeExit" не следует использовать в качестве альтернативы событию "exit", если только намерение заключается в планировании дополнительной работы.

Любые предложения?

Ответ 1

Вы можете перехватить сигналы и выполнить асинхронную задачу перед выходом. Примерно так будет вызывать функцию terminator() перед выходом (даже ошибка JavaScript в коде):

process.on('exit', function () {
    // Do some cleanup such as close db
    if (db) {
        db.close();
    }
});

// catching signals and do something before exit
['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
    'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'
].forEach(function (sig) {
    process.on(sig, function () {
        terminator(sig);
        console.log('signal: ' + sig);
    });
});

function terminator(sig) {
    if (typeof sig === "string") {
        // call your async task here and then call process.exit() after async task is done
        myAsyncTaskBeforeExit(function() {
            console.log('Received %s - terminating server app ...', sig);
            process.exit(1);
        });
    }
    console.log('Node server stopped.');
}

Добавить детали, запрошенные в комментарии:

  • Сигналы, объясненные из документации узла, эта ссылка относится к стандартным именам сигналов POSIX
  • Сигналы должны быть строковыми. Тем не менее, я видел, что другие сделали проверку, поэтому могут быть некоторые другие неожиданные сигналы, о которых я не знаю. Просто хочу убедиться перед вызовом process.exit(). Я полагаю, что проверка все равно не займет много времени.
  • для db.close(), я думаю, это зависит от используемого вами драйвера. Будь то синхронизация асинхронная. Даже если он асинхронный, и вам не нужно ничего делать после закрытия db, тогда все должно быть в порядке, потому что async db.close() просто генерирует событие close, и цикл обработки событий продолжит его обрабатывать независимо от того, завершился ли ваш сервер или нет.

Ответ 2

Использование крючка beforeExit

Событие beforeExit генерируется, когда Node.js очищает свой цикл обработки событий и не имеет никакой дополнительной работы для планирования. Обычно процесс Node.js завершается, когда работа не запланирована, но прослушиватель, зарегистрированный в событии beforeExit, может выполнять асинхронные вызовы и тем самым продолжать процесс Node.js.

process.on('beforeExit', async ()=> {
    await something()
    process.exit(0) // if you don't close yourself this will run forever
}