成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

聊聊各種可能導致 Node.js 進程退出的情況

本篇文章聊聊Node的進程退出,介紹各種可能導致 Node.js 進程退出的情況,希望對大家有所幫助!

聊聊各種可能導致 Node.js 進程退出的情況

在我們的服務發布后,難免會被運行環境(如容器、pm2 等)調度、升級服務導致重啟、各種異常導致進程崩潰;一般情況下,運行環境都有對服務進程的健康監測,在進程異常時,會重新拉起進程,在升級時,也有滾動升級的策略。但運行環境的調度策略是把我們服務的進程當成黑盒來處理的,不會管服務進程內部的運行情況,因此需要我們的服務進程主動感知運行環境的調度動作,然后做一些退出的清理動作。

因此我們今天就是梳理各種可能導致 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 worldn');   }).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

https://github.com/darukjs/daruk-exit-hook

進程優雅退出

通常我們的 web server 在重啟、被運行容器調度(pm2 或者 docker 等)、出現異常導致進程退出時,我們希望執行退出動作,如完成已經連接到服務的請求響應、清理數據庫連接、打印錯誤日志、觸發告警等,做完退出動作后,再退出進程,我們可以使用剛才的進程退出監聽工具實現:

const http = require('http');  // 創建 web server const server = http.createServer((req, res) => {   res.writeHead(200);   res.end('hello worldn'); }).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 進程退出的各種情況心里有數了。在服務上線后,雖然 k8s、pm2 等工具能夠在進程異常退出時,不停地拉起進程,保證服務的可用性,但我們也應該在代碼中主動感知進程的異常或者被調度的情況,從而能夠更早發現問題。

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
日本熟妇色丰满少妇wwwww色| 性色AV无码专区亚洲AV毛片子| 国产一区二区波多野结衣| 亚洲最大AV无码网站| 人妻AV鲁丝一区二区三区蜜臀| 动漫精品中文无码卡通动漫| 舔吮着她的乳尖小说| 皇上撞着小公主的小说叫什么| 在线А√天堂中文官网| 色久综合网精品一区二区| 黑人巨茎中出人妻| AV无码AV无码专区| 西西444WWW大胆无码视频| 裸体美女扒开下部无遮挡网站免费| FREE性欧美HD另类精品| 色婷婷成人综合激情免费视频| 国产欧美精品一区二区三区-老狼| 亚洲自偷自偷在线成人网站传媒| 日日摸夜夜添夜夜添无码免费视频| 无码少妇精品一区二区免费动态| 国产精品午夜无码AV体验区| 在线亚洲熟妇一区二区三 | 无码人妻精品一区二区三区免费| 黑人荫道BBWBBB大荫道| 大香伊蕉AⅤ在人线国产| 伊伊人成亚洲综合人网香| 小妖精含牢了我喂饱你| 人妻色欲AV无码专区精油按摩| 久久久精品人妻久久影视| 国产好爽…又高潮了毛片| 97人妻成人免费视频| 亚洲精品AⅤ无码精品| 日本熟妇色丰满少妇wwwww色| 久久99精品国产麻豆| 从厨房到餐桌JOYCE| 亚洲自偷图片自拍图片| 亚洲AⅤ天堂无码专区-百度| 欧美午夜精品久久久久免费视 | 日本55丰满熟妇厨房伦| 久久水蜜桃网国产无线网欧美日韩| 国产精品成人久久久久久久| 97超碰精品成人国产| 亚洲精品无码AV中文字幕| 国产无人区一码二码三码MBA | 学生妹亚洲一区二区| 日子我妈妈毛片儿电影| 欧美一级内射黑人内射| 老翁的大肉蟒进进出出| 久久久久亚洲AV成人无码网站| 精品卡一卡三卡四卡AⅤ新区| 国产裸体XXXX视频在线播放| 国产成人A∨激情视频厨房| 97porm国内自拍视频| 亚洲无人区一码二码三码区别| 亚洲AV无码AV有码AV| 亚洲XXX午休国产熟女屁| 亚洲AV午夜精品一区二区三区 | 天堂AV旡码AV毛片毛片免费| 朋友人妻少妇精品系列| 欧美〇〇无码黑人大战野结衣| 欧美精品黑人粗大视频| 欧美极品在线观看| 欧 美 伦乱 内射小说| 免费看国产成年无码AV片| 久久久午夜成人噜噜噜| 农村野外性BBW| 内射在线CHINESE| 日本一卡二卡三卡四卡2021| 少妇高潮惨叫喷水在线观看 | 日本XXX色视频在线观看| 色欲av蜜臀一区二区三区vr| 无码人妻一区二区三区免费看| 亚洲AV无码国产精品久久不卡| 亚洲AV无码专区日韩乱码不卡| 亚洲爆乳精品无码一区二区三区 | 伴郎粗大的内捧猛烈进出视频观看| 成人午夜福利免费无码视频| А√新版天堂资源在线BT| 成人中文乱幕日产无线码| 国产精品沙发午睡系列| 久久亚洲精品无码播放| 欧亚一二精品在免费看| 天干夜天干天天爽自慰| 亚洲精品无码久久久久AV老牛| 中文字幕视频在线观看| 成人无码视频在线观看| 国产人成精品香港三级在线| 里番本子库绅士ACG全彩无码| 日本熟妇人妻ⅩXXXX| 亚洲一卡一卡二新区无人区| 啊灬啊灬啊灬快灬高潮少妇软件| 国产精品国产精品国产专区不卡| 久久久亚洲精品无码| 色婷婷综合久久久久中文字幕| 亚洲人成无码网在线观看APP | 中字年轻漂亮的儿媳BD| 国产高清不卡一区二区| 胯下粗长挺进人妻体内电影| 日本强好片久久久久久AAA| 搡老女人老妇老熟女hd| 尤物精品国产第一福利网站| 炖肉计(是今)海棠| 久久久久久精品天堂无码中文字幕| 日韩人妻中文无码一区二区七区| 亚洲综合久久一区二区| 国产成人精品无码专区| 伦人伦XXX国产对白| 亚洲国产AⅤ精品一区二区百度 | 又爽又黄又无遮挡的视频在线观看| 东京热加勒比视频一区| 久久久久久成人毛片免费看| 我的真實亂倫故事| CAOPORN免费视频在线| 精品97国产免费人成视频| 人妻无码系列一区二区三区| 最新国产精品久久精品| 精品人妻一区二区三区视频| 日韩乱码人妻无码系列中文字幕| 亚洲欧美日韩精品色XXX| 国产午夜成人无码免费| 熟妇人妻久久中文字幕老熟妇| 69国产成人精品午夜福中文| 精品国产18久久久久久| 亚洲 欧美 国产 制服 动漫 | 疯狂做受ⅩⅩⅩⅩ高潮高清视频| 日产亚洲一卡2卡3卡4卡网站 | 国产50岁老熟女网站| 欧美最猛黑人AAAAAXXX片| 18精品久久久无码午夜福利| 乱肉怀孕又粗又大| 一二三四在线看日本高清| 饥渴少妇高清VIDEOS| 亚洲AV无码专区在线观看漫画| 国产美女裸体无遮挡免费视频| 熟女高潮精品一区二区绯乐| 大又大又粗又硬又爽少妇毛片| 色偷偷AV男人的天堂| 国产丰滿老熟女多毛hD| 四十路の五十路熟女豊満 | 久久亚洲AV无码精品色午夜麻| 亚洲成av人片在线观看| 九九久久精品国产| 一二三四在线观看免费中文吗| 久久午夜夜伦鲁鲁片无码免费 | 一本一久本久A久久精品综合 | 国产熟妇与子伦HD| 欧美XXXX做受欧美88HD| 67194熟妇在线观看线路| 欧美牲交A欧美牲交AⅤ免费真| 亚洲无码视频一区二区| 精产国品一二三产区区别在哪儿呢| 亚洲男人AV天堂男人社区| 精品无码国产污污污在线观看 | 亚洲国产成人A精品不卡在线 | 国产男男猛烈无遮挡A片小说| 四虎影视成人永久免费观看视频| ZOOM与人性ZOOM1区别| 女人18片毛片60分钟完整版| 车后车座的疯狂的做的视频| 日本丰满的人妻HD高清在线| 被两个男人按住胸吃奶好爽| 破了亲妺妺的处免费视频国产| JΑPΑN丰满人妻HDXXXX| 天堂中文资源库官网| 久久99国产精品成人| YY6090青苹果影院| 小SAO货CAO得你舒服么| 久久久久久亚洲AV无码专区| 99久久无色码中文字幕人妻蜜柚| 天堂M和天堂2M区别| 久久天天躁夜夜躁狠狠I女人| 中文字幕人妻色偷偷久久 | 亚洲欧洲日产国码无码| 人C交ZZZ0OOZZZ000| 狠狠色综合7777久夜色撩人| 97精品国产手机| 午夜.DJ高清在线观看免费7| 麻豆一区二区在我观看| 国产精品色吧国产精品| 一二三四免费观看视频中国 | 边喂奶边中出的人妻| 亚洲AV永久无码精品尤物在线| 秋霞手机在线看秋免费| 精华液一区二区区别| FREE性玩弄妇女HD| 性XXXX视频播放免费| 久久午夜夜伦鲁鲁片免费无码影视| 77色午夜成人影院综合网| 亚洲AV一二三又爽又色又色| 少妇性SEXBBWZⅩX| 色噜噜狠狠狠综合曰曰曰| 日产精品卡2卡三卡乱码网址| 热RE99久久精品国99热| 人畜禽CORPORATION| 欧美老熟妇又粗又大| 人妻插B视频一区二区三区| 男女作爱全部免费观爱| 欧美黑人XXXX性高清版| 欧美做受三级级视频播放| 日本BBWW高潮BBWR|