In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-04 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
Today Xiaobian to share with you what the principle of Node.js process exit is related knowledge points, detailed content, clear logic, I believe most people still know too much about this knowledge, so share this article for everyone to refer to, I hope you have some gains after reading this article, let's learn about it together.
principle
A process to quit, nothing more than two cases, one is the process itself to quit, the other is to receive a system signal, requiring the process to quit.
System signaling exit
Common system signals are listed in the Node.js official documentation, and we focus on a few:
SIGHUP: This signal is triggered by closing the command line terminal directly instead of stopping the process with ctrl+c
SIGINT: triggered when pressing ctrl+c to stop the process;pm2 will also send this signal to the child process when restarting or stopping the child process
SIGTERM: generally used to notify the process to exit gracefully, such as k8s delete pod, it will send SIGTERM signal to pod, pod can do some exit cleaning actions within the timeout period (default 30s)
SIGBREAK: On the window system, pressing ctrl+break triggers this signal.
SIGKILL: Forcefully exit the process, the process cannot do any cleanup action, execute the command kill -9 pid, the process will receive the signal. k8s will send SIGKILL signal to pod to exit pod process immediately if pod has not exited after 30s when deleting pod;pm2 will send SIGKILL signal if process has not exited after 1.6 s when restarting or stopping process
Upon receiving an unforced exit signal, the Node.js process can listen for the exit signal and do some custom exit logic. For example, if we write a cli tool that takes a long time to execute a task, if the user wants to exit the process by ctrl+c before the task is completed, we can prompt the user to wait:
const readline = require ('readline ');process.on ('SIGINT', () => { //We simply implement command-line interactions through readline const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question ('The task is not finished yet, are you sure you want to quit? ', answer => { if (answer === 'yes') { console.log ('Task execution interrupted, exit process'); process.exit(0); } else { console.log ('Task continues... '); } rl.close(); });});//Simulate a task that takes 1 minute to execute const longTimeTask = () => { console.log ('task start... '); setTimeout(() => { console.log('task end'); }, 1000 * 60);};longTimeTask();
The effect is as follows, each time you press ctrl + c will prompt the user:
Process voluntary exit
Node.js process actively exits, mainly including the following situations:
code execution triggers an uncaught error, which can be monitored via process.on ('uncaughtException ')
Code execution triggers an unhandled promise rejection (Node.js v16 initially causes the process to exit), which can be monitored via process.on ('unhandledRejection ')
EventEmitter triggers an unlistened error event
The process.exit function is actively called in the code to exit the process. You can listen through process.on ('exit ').
Node.js event queue is empty, you can simply think that there is no code to execute, you can listen through process.on ('exit ')
We know that pm2 has a daemon effect. When your process exits incorrectly, pm2 will restart your process. We also implement a daemon child process in Node.js cluster mode (in fact, pm2 is similar logic):
const cluster = require ('cluster ');const http = require ('http');const numCPUs = require ('os ').cpus().length;const process = require ('process');//main process code if (cluster.isMaster) { console.log ('start main process: ${process.pid}`); //create worker process for (let i = 0; i) based on cpu kernel
< numCPUs; i++) { cluster.fork(); } // 监听工作进程退出事件 cluster.on('exit', (worker, code, signal) =>{ console.log(`工作进程 ${worker.process.pid} 退出,错误码: ${code || signal}, 重启中...`); // 重启子进程 cluster.fork(); });}// 工作进程代码if (cluster.isWorker) { // 监听未捕获错误事件 process.on('uncaughtException', error => { console.log(`工作进程 ${process.pid} 发生错误`, error); process.emit('disconnect'); process.exit(1); }); // 创建 web server // 各个工作进程都会监听端口 8000(Node.js 内部会做处理,不会导致端口冲突) http.createServer((req, res) => { res.writeHead(200); res.end('hello world\n'); }).listen(8000); console.log(`启动工作进程: ${process.pid}`);}应用实践
上面分析了 Node.js 进程退出的各种情况,现在我们来做一个监听进程退出的工具,在 Node.js 进程退出时,允许使用方执行自己的退出逻辑:
// exit-hook.js// 保存需要执行的退出任务const tasks = [];// 添加退出任务const addExitTask = fn => tasks.push(fn);const handleExit = (code, error) => { // ...handleExit 的实现见下面};// 监听各种退出事件process.on('exit', code => handleExit(code));// 按照 POSIX 的规范,我们用 128 + 信号编号 得到最终的退出码// 信号编号参考下面的图片,大家可以在 linux 系统下执行 kill -l 查看所有的信号编号process.on('SIGHUP', () => handleExit(128 + 1));process.on('SIGINT', () => handleExit(128 + 2));process.on('SIGTERM', () => handleExit(128 + 15));// windows 下按下 ctrl+break 的退出信号process.on('SIGBREAK', () => handleExit(128 + 21));// 退出码 1 代表未捕获的错误导致进程退出process.on('uncaughtException', error => handleExit(1, error));process.on('unhandledRejection', error => handleExit(1, error));
信号编号:
接下来我们要实现真正的进程退出函数 handleExit,因为用户传入的任务函数可能是同步的,也可能是异步的;我们可以借助 process.nextTick 来保证用户的同步代码都已经执行完成,可以简单理解 process.nextTick 会在每个事件循环阶段的同步代码执行完成后执行(理解 process.nextTick);针对异步任务,我们需要用户调用 callback 来告诉我们异步任务已经执行完成了:
// 标记是否正在退出,避免多次执行let isExiting = false;const handleExit = (code, error) => { if (isExiting) return; isExiting = true; // 标记已经执行了退出动作,避免多次调用 let hasDoExit = fasle; const doExit = () => { if (hasDoExit) return; hasDoExit = true process.nextTick(() => process.exit(code)) } // 记录有多少个异步任务 let asyncTaskCount = 0; // 异步任务结束后,用户需要调用的回调 let ayncTaskCallback = () => { process.nextTick(() => { asyncTaskCount-- if (asyncTaskCount === 0) doExit() }) } // 执行所有的退出任务 tasks.forEach(taskFn => { // 如果 taskFn 函数的参数个数大于 1,认为传递了 callback 参数,是一个异步任务 if (taskFn.length > 1) { asyncTaskCount++ taskFn(error, ayncTaskCallback) } else { taskFn(error) } }); // 如果存在异步任务 if (asyncTaskCount > 0) { // 超过 10s 后,强制退出 setTimeout(() => { doExit(); }, 10 * 1000) } else { doExit() }};
至此,我们的进程退出监听工具就完成了,完整的实现可以查看这个开源库 async-exit-hook
进程优雅退出
通常我们的 web server 在重启、被运行容器调度(pm2 或者 docker 等)、出现异常导致进程退出时,我们希望执行退出动作,如完成已经连接到服务的请求响应、清理数据库连接、打印错误日志、触发告警等,做完退出动作后,再退出进程,我们可以使用刚才的进程退出监听工具实现:
const http = require('http');// 创建 web serverconst server = http.createServer((req, res) => { res.writeHead(200); res.end('hello world\n');}).listen(8000);// 使用我们在上面开发的工具添加进程退出任务addExitTask((error, callback) => { // 打印错误日志、触发告警、释放数据库连接等 console.log('进程异常退出', error) // 停止接受新的请求 server.close((error) => { if (error) { console.log('停止接受新请求错误', error) } else { console.log('已停止接受新的请求') } }) // 比较简单的做法是,等待一定的时间(这里我们等待 5s),让存量请求执行完毕 // 如果要完全保证所有请求都处理完毕,需要记录每一个连接,在所有连接都释放后,才执行退出动作 // 可以参考开源库 https://github.com/sebhildebrandt/http-graceful-shutdown setTimout(callback, 5 * 1000)})以上就是"Node.js进程退出的原理是什么"这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un