美文网首页
NODE服务优雅退出

NODE服务优雅退出

作者: 我叫Aliya但是被占用了 | 来源:发表于2023-05-29 10:05 被阅读0次

最近 socket 服务遇到了脏进程的问题,也有人叫僵尸进程,复现步骤基本如下

const cp = require('child_process');

const worker1 = cp.fork('./bin/worker');
const worker2 = cp.fork('./bin/worker');

setTimeout(() => {
  console.info(`主进程关闭`);
  process.exit();
}, 3000);

// bin/worker
setInterval(() => {
  console.info(`子进程 setInterval:`, Date.now());
}, 3000);

无论是process.exit()还是 ctrl+c 结束,主进程关闭后子进程依然在进行,查看 NODE API 发现有这一句:

On Linux, child processes of child processes will not be terminated when attempting to kill their parent.

在 Linux,子进程的子进程不会被终止,当它们的父进程退出时

然后在网上有人说:

默认情况,父进程退出,子进程变为"孤儿进程",孤儿进程会被托管给进程 init,也就是进程 1,所以 kill B 进程,B 进程的子进程 C D 会被托管给进程 1,不会被终止。
请注意“僵尸进程”,你 KILL B 进程的时候 ,A 进程有没有 wait,如果没有会产生僵尸进程。想终止 CD 进程 可以对 CD 执行 kill 操作强制终止,发送 KILL 信号,以及使用 IPC 来通知进程,让进城自己退出。

NODE API 中有提供方法process.kill(pid[, signal]),用于终止指定进程,但如果 PID 已经重新分配给其他进程,信号就会被发送到新的进程里,造成难以复现和排查的错误,且,子进程退出前通常需要做一些收尾工作,比如发出警报,收集日志等,所以直接终止子进程大部分时间也并不适用

最终方案:

// 主
process.on('uncaughtException', (err, origin) => {
  // 记录日志、发起报警
  elegantExit();
});
process.on('exit', elegantExit);
process.on('SIGINT', elegantExit); //catches ctrl+c event
process.on('SIGUSR1', elegantExit); // catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR2', elegantExit);

// 优雅退出
function elegantExit() {
  if (elegantExit.called) return;
  elegantExit.called = true;
  子进程.send({ cmd: 'SIGHUP' }); // 不使用 kill 方法,仅 send 一条 SIGHUP 消息
  process.exit();
}
// 子
process.on('message', ({ cmd }) => {
  if (cmd === 'SIGHUP') exitProcessByMain();
});

process.on('uncaughtException', (err, origin) => {
  // 记录日志、发起报警
  exitProcessByMain();
});

// 优雅退出
function exitProcessByMain() {
  // 3000s 后进程还在,手动结束
  const to = setTimeout(() => process.exit(), 3000);
  to.unref(); // unref 不会把进程保持住
}

关于pm2,它通知会辅助管理进程,比如进程守护和垃圾进程回收(第一个例子使用 pm2 进程启动、停止、重启并不会产生上面的问题)。但实际应用中,子进程会被未断开的连接保持住,导致无法正常结束,且 pm2 在这种情况下并没有正确处理,且,如果这时手动 kill -KILL PID 会触发 pm2 的进程守护,导致这个僵尸进程引发一些无法想象事情

相关文章

  • k8s服务优雅退出

    1 检查当前预估服务支持优雅退出 部署预估服务,rollingUpdate,使用Jmeter一直发压力请求 发现会...

  • proxmox 退出集群

    1、在需要退出集群的node上停止pve-cluster 服务 systemctl stop pve-cluste...

  • docker 优雅退出

    本文主要阐述如何让 docker 容器优雅的终止。 优雅退出定义 所谓优雅退出,指的是程序在退出之前,有清理资源、...

  • 容器退出的时候没有收到kill 信号

    解决node 程序退出时候没有注销Eureka 的问题 现象: 升级服务或者缩容服务的时候,容器关闭的同时未在Eu...

  • npm系列:pm2文档简单翻译

    今天实现了一个用node写了一个小网页放在服务器,为了解决关闭连接后退出node的执行,找了forrver和pm2...

  • 转载:golang 后台服务设计精要

    转载:golang 后台服务设计精要 文章目录 守护进程 优雅的结束进程 响应信号 等待所有协程退出 gorout...

  • Node.js REPL环境操作命令

    输入 node即可进入REPL环境一些常用的命令 退出当前终端 退出Node REPL 补全和Linux命令行一样...

  • JVM优雅退出

    背景 在某个Java应用增加新功能,缩容机器,或者应用以及机器发生异常,通常会停止正在运行的应用,该应用通常正在运...

  • SpringBoot 优雅退出

    欢迎转载,但请在开头或结尾注明原文出处【blog.chaosjohn.com】[https://blog.chao...

  • Nodejs 优雅退出

    前言 我们在Nodejs业务逻辑复杂的时候,很难做到完全没有内存泄漏,和出现uncaughtException的异...

网友评论

      本文标题:NODE服务优雅退出

      本文链接:https://www.haomeiwen.com/subject/hruuldtx.html