我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Node.js进程退出的原理是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Node.js进程退出的原理是什么

今天小编给大家分享一下Node.js进程退出的原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    原理

    一个进程要退出,无非就是两种情况,一是进程自己主动退出,另外就是收到系统信号,要求进程退出。

    系统信号通知退出

    在 Node.js 官方文档 中列出了常见的系统信号,我们主要关注几个:

    • SIGHUP:不通过 ctrl+c 停止进程,而是直接关闭命令行终端,会触发该信号

    • SIGINT:按下 ctrl+c 停止进程时触发;pm2 重启或者停止子进程时,也会向子进程发送该信号

    • SIGTERM:一般用于通知进程优雅退出,如 k8s 删除 pod 时,就会向 pod 发送 SIGTERM 信号,pod 可以在超时时间内(默认 30s)做一些退出清理动作

    • SIGBREAK:在 window 系统上,按下 ctrl+break 会触发该信号

    • SIGKILL:强制退出进程,进程无法做任何清理动作,执行命令 kill -9 pid,进程会收到该信号。k8s 删除 pod 时,如果超过 30s,pod 还没退出,k8s 会向 pod 发送 SIGKILL 信号,立即退出 pod 进程;pm2 在重启或者停止进程时,如果超过 1.6s,进程还没退出,也会发送 SIGKILL 信号

    在收到非强制退出信号时,Node.js 进程可以监听退出信号,做一些自定义的退出逻辑。比如我们写了一个 cli 工具,需要比较长的时间执行任务,如果用户在任务执行完成前想要通过 ctrl+c 退出进程时,可以提示用户再等等:

    const readline = require('readline');process.on('SIGINT', () => {  // 我们通过 readline 来简单地实现命令行里面的交互  const rl = readline.createInterface({    input: process.stdin,    output: process.stdout  });  rl.question('任务还没执行完,确定要退出吗?', answer => {    if (answer === 'yes') {      console.log('任务执行中断,退出进程');      process.exit(0);    } else {      console.log('任务继续执行...');    }    rl.close();  });});// 模拟一个需要执行 1 分钟的任务const longTimeTask = () => {  console.log('task start...');  setTimeout(() => {    console.log('task end');  }, 1000 * 60);};longTimeTask();

    实现效果如下,每次按下 ctrl + c 都会提示用户:

    Node.js进程退出的原理是什么

    进程主动退出

    Node.js 进程主动退出,主要包含下面几种情况:

    • 代码执行过程中触发了未捕获的错误,可以通过 process.on('uncaughtException') 监听这种情况

    • 代码执行过程中触发了未处理的 promise rejection(Node.js v16 开始会导致进程退出),可以通过 process.on('unhandledRejection') 监听这种情况

    • EventEmitter 触发了未监听的 error 事件

    • 代码中主动调用 process.exit 函数退出进程,可以通过 process.on('exit') 监听

    • Node.js 的事件队列为空,可简单认为没有需要执行的代码了,可以通过 process.on('exit') 监听

    我们知道 pm2 有守护进程的效果,在你的进程发生错误退出时,pm2 会重启你的进程,我们也在 Node.js 的 cluster 模式下,实现一个守护子进程的效果(实际上 pm2 也是类似的逻辑):

    const cluster = require('cluster');const http = require('http');const numCPUs = require('os').cpus().length;const process = require('process');// 主进程代码if (cluster.isMaster) {  console.log(`启动主进程: ${process.pid}`);  // 根据 cpu 核数,创建工作进程  for (let i = 0; i < 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));

    信号编号:

    Node.js进程退出的原理是什么

    接下来我们要实现真正的进程退出函数 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进程退出的原理是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    Node.js进程退出的原理是什么

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    Node.js进程退出的原理是什么

    今天小编给大家分享一下Node.js进程退出的原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。原理一个进程要退出,无
    2023-06-29

    NodeJS进程是怎么退出的

    本篇内容介绍了“NodeJS进程是怎么退出的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录前言主动退出Exceptions, Rejec
    2023-06-20

    ubuntu退出程序的方法是什么

    这篇文章主要讲解了“ubuntu退出程序的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“ubuntu退出程序的方法是什么”吧!打开命令行窗口,通过以下命令杀掉对应的进程来退出。方法
    2023-07-04

    Nginx中进程管理和重载的原理是什么

    本篇文章给大家分享的是有关Nginx中进程管理和重载的原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。进程结构图Nginx是多进程结构,多进程结构设计是为了保证Ngin
    2023-06-14

    android退出app的方法是什么

    在 Android 中,退出应用程序的方法有两种:1. 使用系统的返回键:在应用程序的任何界面中,按下系统的返回键即可退出应用程序。2. 使用代码实现:在应用程序的任何界面中,调用以下代码即可退出应用程序:```finishAffinity
    2023-05-29

    Node.js中的进程与子进程怎么处理

    这篇文章主要讲解了“Node.js中的进程与子进程怎么处理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Node.js中的进程与子进程怎么处理”吧!进程:process模块process 模
    2023-07-04

    ubuntu从guest退出的方法是什么

    这篇文章主要介绍“ubuntu从guest退出的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ubuntu从guest退出的方法是什么”文章能帮助大家解决问题。1.打开终端,输入以下命令关
    2023-07-04

    Shell退出状态的用法是什么

    这篇文章主要介绍“Shell退出状态的用法是什么”,在日常操作中,相信很多人在Shell退出状态的用法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Shell退出状态的用法是什么”的疑惑有所帮助!接下来
    2023-06-09

    退出Vim的技巧分别是什么

    今天就跟大家聊聊有关8种花式退出Vim的技巧分别是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。程序员们最常用的代码编辑器是什么,Vim、Emacs、VS Code、Sublim
    2023-06-15

    Linux exit函数与进程退出时信号的处理

    在Linux中,exit()函数和信号处理是两个不同的概念,但它们都与进程的退出有关exit()函数:exit()函数是一个C库函数,用于正常终止进程。当一个程序调用exit()函数时,它会执行以下操作:关闭所有打开的文件描述符释放进程
    Linux exit函数与进程退出时信号的处理
    2024-08-30

    Linux exit函数与进程退出时的清理工作

    在 Linux 系统中,当一个进程退出时,操作系统会执行一系列的清理工作以确保资源得到正确释放关闭所有打开的文件描述符:操作系统会关闭进程打开的所有文件描述符,包括普通文件、套接字等。这样可以确保其他进程不会因为这些文件描述符而无法访问这些
    Linux exit函数与进程退出时的清理工作
    2024-08-30

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录