如何在退出时执行异步操作

Kes*_*vid 17 asynchronous process terminate node.js typescript

在我的进程终止之前,我一直在尝试执行异步操作.

说"终止"是指终止的所有可能性:

  • ctrl+c
  • 未捕获的异常
  • 崩溃
  • 代码结束
  • 什么..]

据我所知,exit事件是这样做的,但对于同步操作.

阅读Nodejs文档我发现该beforeExit事件是针对异步操作但是:

对于导致显式终止的条件,例如调用process.exit()或未捕获的异常,不会发出'beforeExit'事件.

除非打算安排额外的工作,否则不应将'beforeExit'用作'退出'事件的替代方案.

有什么建议?

Sce*_*eat 14

使用 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
});
Run Code Online (Sandbox Code Playgroud)

  • 他们在文档中说,当在代码中的某处显式调用 process.exit() 或发生未发生的异常时,不会发出“beforeExit”,这使得它的使用相当有限。来源:https://nodejs.org/api/process.html#process_event_beforeexit (4认同)

Ben*_*Ben 12

您可以在退出之前捕获信号并执行异步任务.这样的东西会在退出之前调用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.');
}
Run Code Online (Sandbox Code Playgroud)

添加评论中要求的详细信息

  • 从节点文档中解释的信号,此链接指的是标准POSIX信号名称
  • 信号应该是字符串.但是,我已经看到其他人已经完成了检查,因此可能还有其他一些我不知道的意外信号.只是想在调用process.exit()之前确保.我认为无论如何都不需要花太多时间来检查.
  • 对于db.close(),我想这取决于您使用的驱动程序.是否同步异步.即使它是异步的,并且在db关闭后你不需要做任何事情,那么它应该没问题,因为异步db.close()只发出close事件,并且无论你的服务器是否退出,事件循环都将继续处理它.

  • @KesemDavid 实际上就在这里。在(很可能)“db.close()”是异步的情况下,从“exit”事件处理程序调用 if [不保证其执行](https://nodejs.org/dist/latest/docs /api/process.html#process_event_exit)。查看下面的一些答案,了解更严格的实现。 (2认同)

Ron*_* S. 7

结合答案+处理未捕获的异常和承诺拒绝

async function exitHandler(evtOrExitCodeOrError: number | string | Error) {
  try {
    // await async code here
    // Optionally: Handle evtOrExitCodeOrError here
  } catch (e) {
    console.error('EXIT HANDLER ERROR', e);
  }

  process.exit(isNaN(+evtOrExitCodeOrError) ? 1 : +evtOrExitCodeOrError);
}

[
  'beforeExit', 'uncaughtException', 'unhandledRejection', 
  'SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 
  'SIGABRT','SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 
  'SIGUSR2', 'SIGTERM', 
].forEach(evt => process.on(evt, exitHandler));
Run Code Online (Sandbox Code Playgroud)


Nic*_*one 5

这是我对此的看法。在这里作为代码片段发布有点长,所以分享一个 Github 要点。

https://gist.github.com/nfantone/1eaa803772025df69d07f4dbf5df7e58

这很简单。你像这样使用它:

'use strict';
const beforeShutdown = require('./before-shutdown');

// Register shutdown callbacks: they will be executed in the order they were provided
beforeShutdown(() => db.close());
beforeShutdown(() => server.close());
beforeShutdown(/* Do any async cleanup */);
Run Code Online (Sandbox Code Playgroud)

以上将侦听一组特定的系统信号(SIGINT, aka Ctrl+CSIGTERM默认情况下)并在关闭整个进程之前按顺序调用每个处理程序。

它也是,

  • 支持async回调(或返回 a Promise)。
  • 警告关闭处理程序失败,但防止错误/拒绝冒泡。
  • 如果处理程序在一段时间(默认为 15 秒)后没有返回,则强制关闭。
  • 可以从代码库中的任何模块注册回调。

  • 您能澄清一下它如何支持异步回调吗?您的要点依赖于 `process.once()` 。“process.once('SIGTERM', handler)”的处理程序是一个同步函数。我确信异步回调被调用,但在其返回的承诺完成之前不能保证它会运行。你有测试表明它会吗? (3认同)