谈退出之前我们还是先谈谈开始一个 Node.js 程序吧。
- 实用
node
命令来运行一个 js 程序,例如:node server.js
- 运用封装的命令启动一个服务, 例如:
next dev
如果服务的话,node.js 程序不会退出,会在后台启动一个服务进程。由于有了这个服务的进程,就会占有 CPU 资源,在适当的时候,需要退出这个进程,也就是退出这个 Node.js 程序。
Node.js 退出方式
- 系统级信号被动通知退出
- 自己要退出
这个和进入职场和出职场一样,要么主动要么被动。
系统级信号
信号名 | 描述 |
---|---|
SIGABRT | 发生致命错误时发出的信号,通常表示需要立即终止进程。 |
SIGALRM | 定时器超时时发出的信号。 |
SIGHUP | 在控制终端关闭时,操作系统会向进程发送 SIGHUP 信号。 |
SIGILL | 发生非法指令时发出的信号,通常表示需要立即终止进程。 |
SIGINT | 用户终端(例如按下 Ctrl+C )发出的中断信号,通常表示要求进程退出。 |
SIGKILL | 无法被捕获或处理的信号,通常表示需要立即终止进程。 |
SIGPIPE | 向一个已经关闭的 socket 写入数据时发出的信号。 |
SIGQUIT | 类似于 SIGINT 信号,但是会在进程退出前产生 core dump 文件。 |
SIGTERM | 操作系统发出的终止进程信号。 |
SIGUSR1 | 用户自定义信号 1。 |
SIGUSR2 | 用户自定义信号 2。 |
SIGTRAP | 调试器使用的信号,通常不会出现在普通进程中。 |
SIGSYS | 发生系统调用错误时发出的信号。 |
SIGXCPU | 进程使用 CPU 时间过长时发出的信号。 |
SIGXFSZ | 进程尝试写入一个文件,但文件大小超过文件系统的限制时发出的信号。 |
经常遇到的两个信号:
- SIGHUP 关闭终端系统发送信号
- SIGINT 使用
CTRL + C
发送给 Node.js 的关闭进程信号
process.on('SIGINT', function () {
console.log('收到 SIGINT 信号,开始优雅退出...');
// 清理工作...
process.exit();
});
// 钩子:即将退出之前
process.on('beforeExit', function () {
console.log('即将退出,开始清理工作...');
// 清理工作...
});
// 开始退
process.on('exit', function () {
console.log('退出,开始最后的清理工作...');
// 清理工作...
});
process.exit 退出不同类型
- 0:表示进程成功完成。
- 1:表示进程发生了未知的错误。
- 2:表示进程调用了不正确的命令或参数。
- 3:表示进程发生了内部错误或异常。
- 4:表示进程被强制终止。
例如:要写一个命令行,但是参数长度给的不够,可使用编号 1 来退出错误
if (process.argv.length !== 3) {
console.error('Usage: node script.js <filename>'); // 退出前要输出错误
process.exit(1); // 退出并返回退出码 1
}
pm2 和 docker 如何停止 Node.js 进程
- 使用 pm2 stop 命令发送系统进程命令
SIGINT
来停止当前 Node.js - 使用 docker stop 命令,先给容器中的进程发送
SIGTERM
, 完成清理工作,其次就是docker 还执行强制措施SIGKILL
来强制停止应用程序。
当然也可以手动添加监听代码用于监听 SIGINT/SIGTERM
事件,然后执行一些清理等任务。
未捕获的异常与错误
以下是一些常用的 process.on()
方法的事件类型及其说明:
事件类型 | 说明 |
---|---|
uncaughtException | 当一个未被捕获的异常(exception)被抛出时触发。 |
unhandledRejection | 当一个 Promise 被 reject,并且没有对应的 catch() 时触发。 |
warning | 当 Node.js 发出一个警告(warning)时触发。 |
当然 Node.js 可以在未捕获的异常发生错误时,退出程序:
process.on('uncaughtException', (error) => {
console.error('Uncaught exception:', error);
process.exit(1);
});
// 抛出一个未被处理的异常
throw new Error('Unhandled exception');
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled rejection:', reason);
process.exit(1);
});
// 抛出一个未被处理的 Promise rejection
Promise.reject(new Error('Unhandled rejection'));
Remix cli 中如何退出应用程序
import { cli } from "./index";
cli.run().then(
() => {
process.exit(0);
},
(error: unknown) => {
if (error) console.error(error);
process.exit(1);
}
);
cli 中调用 run 方法,run 是个 promise, 在 promise 完成任务会后 exit(0). 但是如果发生了错误,输出错误停止退出。
prisma seed.ts 初始化错误退出
seed()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
小结
优雅退出 Node.js 应用程序,分为主动退出和系统级退出,主动退出常用的分为两种一种是 CTRL + C
和另外一种直接关闭终端工具,本质是用户手动操作,让系统发送命令给 Node.js 进程,停止应用程序。
process.exit 函数根据不同类型进行退出。使用 0 表示成功退出,使用 1 表示有未知错误退出(错误一般用 try-catch 捕获,如果使用 promise 使用 catch 捕获,然后 console 输出)。