【Node】Node中如何守护进程
2023/02/08 10:42:14
捕获抛到全局的异常
NodeJS 环境中如果出现了未捕获的异常会导致进程崩溃,可以用 process 的 uncaughtException 事件来捕获这些异常:
process.on("uncaughtException", (e) => {
console.error("process error is:", e.message);
});
然后在事件处理程序中重启应用:
process.on("uncaughtException", (e) => {
console.error("process error is:", e.message);
restartServer(); // 重启服务
});
这种处理方式可能会导致内存泄漏:当异常出现时,直接从对应执行栈中断,而到 process 捕获的异常事件下,导致了 v8 引擎的垃圾回收功能不能按照正常流程工作,然后开始出现内存泄漏问题。
利用 domain 模块来守护进程
使用 domain 模块也能达到同样的效果,但是同样会出现内存泄漏的问题。
import domain from "domain";
const d = domain.create();
const dot = 3;
let count = 0;
function task() {
console.log(count++, dot);
if (count === dot) {
throw new Error();
}
setTimeout(task, 1000);
}
d.on("error", (error) => {
console.log("err", error);
d.run(task);
});
d.run(task);
多进程模式加异常捕获后重启
以多进程模式去部署应用,当某一个进程触发全局异常捕获后,重启该进程释放内存,此时其他进程可以继续提供服务。
const cluster = require("cluster");
const os = require("os");
const http = require("http");
const domain = require("domain");
const d = domain.create();
if (cluster.isMaster) {
const cpuNum = os.cpus().length;
for (let i = 0; i < cpuNum; ++i) {
cluster.fork();
}
// fork work log
cluster.on("fork", (worker) => {
console.info(`${new Date()} worker${worker.process.pid}进程启动成功`);
});
// 监听异常退出进程,并重新fork
cluster.on("exit", (worker, code, signal) => {
console.info(`${new Date()} worker${worker.process.pid}进程启动异常退出`);
cluster.fork();
});
} else {
http
.createServer((req, res) => {
d.add(res);
d.on("error", (err) => {
console.log("记录的err信息", err.message);
console.log("出错的 work id:", process.pid);
// uploadError(err) // 上报错误信息至监控
res.end("服务器异常, 请稍后再试");
// 将异常子进程杀死
cluster.worker.kill(process.pid);
});
d.run(handle.bind(null, req, res));
})
.listen(8080);
}
function handle(req, res) {
if (process.pid % 2 === 0) {
throw new Error(`出错了`);
}
res.end(`response by worker: ${process.pid}`);
}