




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第聊聊各种可能导致Node.js进程退出的情况实现效果如下,每次按下ctrl+c都会提示用户:
进程主动退出
Node.js进程主动退出,主要包含下面几种情况:
代码执行过程中触发了未捕获的错误,可以通过process.on(uncaughtException)监听这种情况
代码执行过程中触发了未处理的promiserejection(Node.jsv16开始会导致进程退出),可以通过process.on(unhandledRejection)监听这种情况
EventEmitter触发了未监听的error事件
代码中主动调用process.exit函数退出进程,可以通过process.on(exit)监听
Node.js的事件队列为空,可简单认为没有需要执行的代码了,可以通过process.on(exit)监听
我们知道pm2有守护进程的效果,在你的进程发生错误退出时,pm2会重启你的进程,我们也在Node.js的cluster模式下,实现一个守护子进程的效果(实际上pm2也是类似的逻辑):
constcluster=require(cluster
consthttp=require(http
constnumCPUs=require(os).cpus().length;
constprocess=require(process
//主进程代码
if(cluster.isMaster){
console.log(`启动主进程:${process.pid}`);
//根据cpu核数,创建工作进程
for(leti=0;inumCPUs;i++){
cluster.fork();
//监听工作进程退出事件
cluster.on(exit,(worker,code,signal)={
console.log(`工作进程${cess.pid}退出,错误码:${code||signal},重启中...`);
//重启子进程
cluster.fork();
//工作进程代码
if(cluster.isWorker){
//监听未捕获错误事件
process.on(uncaughtException,error={
console.log(`工作进程${process.pid}发生错误`,error);
process.emit(disconnect
process.exit(1);
//创建webserver
//各个工作进程都会监听端口8000(Node.js内部会做处理,不会导致端口冲突)
http.createServer((req,res)={
res.writeHead(200);
res.end(helloworld\n
}).listen(8000);
console.log(`启动工作进程:${process.pid}`);
}
应用实践
上面分析了Node.js进程退出的各种情况,现在我们来做一个监听进程退出的工具,在Node.js进程退出时,允许使用方执行自己的退出逻辑:
//exit-hook.js
//保存需要执行的退出任务
consttasks=[];
//添加退出任务
constaddExitTask=fn=tasks.push(fn);
consthandleExit=(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来告诉我们异步任务已经执行完成了:
//标记是否正在退出,避免多次执行
letisExiting=false;
consthandleExit=(code,error)={
if(isExiting)return;
isExiting=true;
//标记已经执行了退出动作,避免多次调用
lethasDoExit=fasle;
constdoExit=()={
if(hasDoExit)return;
hasDoExit=true
process.nextTick(()=process.exit(code))
//记录有多少个异步任务
letasyncTaskCount=0;
//异步任务结束后,用户需要调用的回调
letayncTaskCallback=()={
process.nextTick(()={
asyncTaskCount--
if(asyncTaskCount===0)doExit()
//执行所有的退出任务
tasks.forEach(taskFn={
//如果taskFn函数的参数个数大于1,认为传递了callback参数,是一个异步任务
if(taskFn.length1){
asyncTaskCount++
taskFn(error,ayncTaskCallback)
}else{
taskFn(error)
//如果存在异步任务
if(asyncTaskCount0){
//超过10s后,强制退出
setTimeout(()={
doExit();
},10*1000)
}else{
doExit()
};
至此,我们的进程退出监听工具就完成了,完整的实现可以查看这个开源库async-exit-hook
/darukjs/daruk-exit-hook
进程优雅退出
通常我们的webserver在重启、被运行容器调度(pm2或者docker等)、出现异常导致进程退出时,我们希望执行退出动作,如完成已经连接到服务的请求响应、清理数据库连接、打印错误日志、触发告警等,做完退出动作后,再退出进程,我们可以使用刚才的进程退出监听工具实现:
consthttp=require(http
//创建webserver
constserver=http.createServer((req,res)={
res.writeHead(200);
res.end(helloworld\n
}).listen(8000);
//使用我们在上面开发的工具添加进程退出任务
addExitTask((error,callback)={
//打印错误日志、触发告警、释放数据库连接等
console.log(进程异常退出,error)
//停止接受新的请求
server.close((error)={
if(error){
console.log(停止接受新请求错误,error)
}else{
console.log(已停止接受新的请求)
//比较简单的做法是,等待一定的时间(这里我们等待5s),让存量请求执行完毕
//如果要完全保证所有请求都处理完毕,需要记录每一个连接,在所有连接都释放后,才执行退出动作
//可以参考开源库/seb
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论