Artikel ini membincangkan tentang proses keluar Node dan memperkenalkan pelbagai situasi yang mungkin menyebabkan proses Node.js keluar. Saya harap ia akan membantu semua orang.
Selepas perkhidmatan kami dikeluarkan, ia pasti akan dijadualkan oleh persekitaran operasi (seperti bekas, pm2, dll.), peningkatan perkhidmatan akan menyebabkan dimulakan semula, dan pelbagai pengecualian akan menyebabkan proses ranap; secara umum Seterusnya, persekitaran operasi mempunyai pemantauan kesihatan proses perkhidmatan Apabila proses tidak normal, proses akan dimulakan semula Apabila menaik taraf, terdapat juga strategi naik taraf. Walau bagaimanapun, strategi penjadualan persekitaran berjalan menganggap proses perkhidmatan kami sebagai kotak hitam dan tidak mengambil berat tentang keadaan berjalan dalaman proses perkhidmatan Oleh itu, proses perkhidmatan kami perlu secara aktif merasakan tindakan penjadualan persekitaran berjalan dan kemudian melaksanakan beberapa tindakan pembersihan keluar .
Jadi hari ini kita akan menyelesaikan pelbagai situasi yang mungkin menyebabkan proses Node.js keluar dan perkara yang boleh kita lakukan dengan mendengar peristiwa keluar proses ini.
Prinsip
Satu proses perlu keluar dalam dua situasi iaitu proses itu keluar atas inisiatifnya sendiri, dan satu lagi ialah itu ia menerima isyarat sistem Minta proses untuk keluar.
Pemberitahuan isyarat sistem untuk keluar
Isyarat sistem biasa disenaraikan dalam dokumen rasmi Node.js Kami memberi tumpuan terutamanya kepada beberapa:
Apabila menerima isyarat keluar tanpa paksa, proses Node.js boleh mendengar isyarat keluar dan melakukan beberapa keluar tersuai. logik. Sebagai contoh, kami menulis alat cli yang mengambil masa yang lama untuk melaksanakan tugasan Jika pengguna ingin keluar dari proses melalui ctrl c sebelum tugasan selesai, pengguna boleh digesa untuk menunggu:
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();
Proses keluar secara aktif
Proses Node.js keluar secara aktif, terutamanya Termasuk situasi berikut: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}`); }
Di atas telah menganalisis pelbagai situasi proses keluar Node.js untuk memantau proses keluar. Apabila proses Node.js keluar, pengguna dibenarkan untuk melaksanakan logik keluarnya sendiri:
Nombor isyarat:
// 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
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 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 进程退出的各种情况心里有数了。在服务上线后,虽然 k8s、pm2 等工具能够在进程异常退出时,不停地拉起进程,保证服务的可用性,但我们也应该在代码中主动感知进程的异常或者被调度的情况,从而能够更早发现问题。
更多node相关知识,请访问:nodejs 教程!
Atas ialah kandungan terperinci Mari kita bincangkan tentang pelbagai situasi yang mungkin menyebabkan proses Node.js keluar. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!