当前位置:首页 > 日记 > 正文

详解node中创建服务进程

详解node中创建服务进程

背景

在node工程部署中,常常涉及到三方:本地客户端、跳板机和服务器(集群)。在通过git触发gitlab hook脚本后,需要在跳板机中执行相应的ssh命令执行shell文件启动node服务器,这需要使用一个常用的命令setsid,这样当ssh命令执行完毕shell退出后,node服务器仍正常运行,此时node服务进程就是一个最典型的daemon进程(后台服务进程)。

那么,在node项目中,如何创建一个daemon进程呢?最简单的方式,其实就是采用类似上文中介绍的方式:

复制代码 代码如下:
require('child_process').exec('setsid node app.js >/dev/null 2>&1 &');

这样可以通过执行shell的方式实现daemon进程。不过本文的重点并不是介绍这种“命令行”的方式实现daemon进程,而且本文会详细讲述daemon进程的创建原理,且看下文。

目标

在当前业务中,之所以需要创建daemon进程就是为了保证中断创建该进程的父进程(ctrl+c)或者父进程执行完毕后并不影响daemon进程的执行。下文介绍两种实现方式,实现原理细节上有些出入。

下文中的所有讨论都是在linux环境下进行。

实现一

在linux系统中,父进程创建出子进程,此时父进程若退出,此时子进程则变为孤儿进程,其ppid变为1,即成为init进程的子进程。在node环境下,如果不针对子进程的stdio做一些特殊处理父进程其实不会真正退出,而是直到子进程执行完毕后再退出。之所以出现这种情况是由于node创建子进程时默认会通过pipe方式将子进程的输出导流到父进程的stream中(childProcess.stdout、childProcess.stderr),提供在父进程中输出子进程消息的能力。

因此,解决此种问题可给子进程的stdio重新赋值:

file: parent.jslet cp = require('child_process');const sp = cp.spawn('node',['./c.js'],{  stdio: [process.stdin,process.stdout,process.stderr]});setTimeout(()=>{console.log('parent out')},5000);--------------file: c.jssetTimeout(()=>{  console.log('children exit');},10000)

通过在parent.js中设置子进程的stdio为当前终端(其实继承了父进程的stdio),这样父进程在5s后退出,此时子进程的ppid变为1,10s后子进程退出。

上述实现只满足“父进程正常退出,子进程成为守护进程”的情况,一旦通过“ctrl+c”的方式终端父进程,子进程仍会退出,这还是与node底层实现有关。默认“ctrl+c”触发SIGINT信号,父进程接受信号后发送给子进程,如果子进程存在SIGINT侦听函数,则会执行该函数,否则执行exit系统调用子进程退出。因此,如果要让子进程在接收到SIGINT信号不退出,只需要不作处理即可:

file: c.jsprocess.on('SIGINT',function(){  console.log('child sigint');});setTimeout(()=>{  console.log('children exit');},10000)

以上实现,可以满足我们最初指定的目标:“父进程退出或者中断,子进程仍正常运行”。

 实现二

node官方提供了创建daemon进程的相关API,如果不仔细阅读文档还真不容易发现该特性。在child_process模块中有个spawn函数,通过spawn可以执行shell命令及其相关选项,同时spawn提供了创建子进程的一些选项,其中“detached”选项则与我们的需求密切相关。

detached选项可以让node原生帮我们创建一个daemon进程,设置datached为true可以创建一个新的session和进程组,子进程的pid为新创建进程组的组pid,这与setsid起到相同的作用。此时的子进程已经和其父进程属于两个session,因此父进程的退出和中断信号不会传递给子进程,子进程不会接受到父进程的中断信号自然也不会退出。当父进程结束之后,子进程变为孤儿进程从而被init进程接收,ppid设置为1。

file: parent.jslet cp = require('child_process');const sp = cp.spawn('node',['./c.js'],{  detached: true,  stdio: [process.stdin,process.stdout,process.stdout]});sp.unref();setTimeout(()=>{console.log('parent out')},5000);----------------------file: c.jssetTimeout(()=>{  console.log('children exit');},100000)

此时,c.js文件并未设置SIGINT事件侦听函数,在父进程中断后仍会正常运行,正是由于其和父进程分属于两个session。

在parent.js文件中设置了sp.unref()函数,目的是“避免父进程等待子进程退出”。那么为何会出现上述情况呢?这与node的事件循环有关,让父进程的事件循环排除对ChildProcess子进程对象的引用,可以使父进程单独退出。

总结

为什么上文介绍的两个方法都可以实现daemon进程呢?这还得回到系统层面进行分析。在linux系统创建一个daemon进程需要几个步骤:

1.父进程创建子进程,父进程退出,让子进程成为孤儿进程,ppid=1

2.通过setsid命令或函数在子进程中创建新的会话和进程组

3.设置当前目录

4.设置文件权限,并关闭父进程继承打开的fd

所谓会话和进程组,则是在linux多任务多用户下的概念。不同会话的进程无法通过通信,因此父子进程相隔离。而执行setsid命令则让子进程有了新的特性:

  1. 子进程脱离父进程所在的session控制,两者独立存在互不影响
  2. 子进程脱离父进程所在的进程组
  3. 子进程脱离原先的命令行终端,终端退出不影响子进程

下面再回顾方法一与方法二的区别,发现方法一其实并不是真正的daemon进程,只是通过侦听相关中断信号并设置nop函数(不执行默认的中断行为)保证子进程继续运行而已;而方法二则是标准的deamon进程创建方式,优先使用!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

相关文章

微信筹款怎么弄微信普通筹款的使用

微信筹款怎么弄微信普通筹款的使用

使用方法,怎么弄,电脑软件,strong,  普通筹款是微信新上线的一个功能,那么微信筹款怎么使用呢?下面是小编为大家整编的微信普通筹款的使用方法,大家快来看看吧。微信普通筹款的使用方法1)打开微信应用进入页面点击下方【我】,接着点击【钱包…

js实现点击切换checkbox背景的简单

js实现点击切换checkbox背景的简单

简单实例,背景,电脑软件,js,checkbox,在制作网页的过程中,经常需要实现点击切换背景图片的效果,本文关注的是表单中checkbox背景图片切换的实现。如图,在输入用户名和密码后,用户需要选择是否记住密码图片背景为白色表示未勾选状态 。HTML源码…

详谈js中标准for循环与foreach | f

详谈js中标准for循环与foreach | f

循环,区别,标准,电脑软件,js,js中遍历数组的有两种方式var array=['a']//标准的for循环for(var i=1;i<array.length;i++){ alert(array[i])}//foreach循环for(var i in array){ alert(array[i])}正常情况下上面两种遍历数组的方式结果…

对称加密与非对称加密优缺点详解

对称加密与非对称加密优缺点详解

对称加密,优缺点,与非,详解,电脑软件,对称加密:双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密。优点:速度快,对称性加密通常在消息发送方需要加密大量数据时使用,算法公开、计算量小、加密速度快、加密效…

Java中int与integer的区别(基本数据

Java中int与integer的区别(基本数据

引用数据类型,基本数据类型,区别,电脑软件,Java,一、先说说int与integer的区别  int 是基本数据类型,默认值为0,不需要进行实例化integer 是引用数据类型,是int的封装类型,默认值为null,创建该类型需要进行实例化。基本数据类型是可以用“==”…

全图型PPT的制作方法是什么样的

全图型PPT的制作方法是什么样的

制作方法,全图,电脑软件,PPT,  图片视觉要有冲击力 ,文字精炼要有内涵,这就是全图型PPT!以下是小编为您带来的关于全图型PPT的制作方法,希望对您有所帮助。全图型PPT的制作方法一、大图配字二、艺术字体三、借图发挥四、蒙版色变五、色块切…

JavaScript中document.referrer的

JavaScript中document.referrer的

详解,电脑软件,JavaScript,document,referrer,前言在JavaScript中,document对象有很多属性,其中有3个与对网页的请求有关的属性,它们分别是URL、domain和referrer。URL属性包含页面完整的URL,domain属性中只包含页面的域名,而referrer属性中则保…

个性情侣签名一男一女逗比最新版一

个性情侣签名一男一女逗比最新版一

一女,情侣,个性,最新版,个性签名,  个性签名丰富多彩,反映出网民的不同的思想、心情等,透过个性签名折射出当代网民的文化心理,下面是个性情侣签名一男一女逗比,希望你喜欢。个性情侣签名一男一女逗比【经典篇】既然选择了我,那就不要抛弃我…

ppt文件中插入柱形图图表的方法是

ppt文件中插入柱形图图表的方法是

文件,方法,图图,电脑软件,ppt,  PPT的使用是必不可少的,自然很多时候我们也会用到图表,以此来更清晰明了的展示数据。ppt文件中想要插入柱形图图表,该怎么设置?以下是小编为您带来的关于ppt文件中插入柱形图图表,希望对您有所帮助。ppt文件中…

excel表格将打印预览功能怎么添加

excel表格将打印预览功能怎么添加

工具栏,表格,功能,电脑软件,excel,  在excel中, 在打印预览界面看到的版面效果,就是实际打印输出后的实际效果;因此,通过打印预览,可以非常直观地检查版面是否符合要求。以下是小编为您带来的关于excel表格将打印预览功能添加到工具栏,希望对…

Excel2013中如何设置加密区域单元

Excel2013中如何设置加密区域单元

加密,区域,方法,单元格,如何设置,  平常在使用excel的时候我们都知道怎么给自己的表格设置密码,这样子的话只有知道密码的人才可以修改excel表格。那么如果我们不想给自己的表格加密,只想给部分的单元格设置密码,下面给大家分享Excel2013加…

WPS文字表格怎么设置增加宽度

WPS文字表格怎么设置增加宽度

文字,方法,设置,宽度,表格,  用表格制作客户资料,有ABCD个选项,有时候需要输入过多的文字,表格宽度不够,需要拉宽一些,应该如何来拉宽?下面小编以WPS这个软件为例子来详细说说:WPS文字表格增加宽度的方法。WPS文字表格增加宽度的方法打开表格,在…