Node应用如何以守护进程启动

我们来编写一个Node最简单的应用app.js

const http = require('http')

const app = http.createServer()

app.on('request',(req,res)=>{

   res.setHeader('Content-Type','text/html;charset=utf8')

   res.end('hello world')
})

app.listen('3000',()=>{

  console.log('running')

})

下面我们来启动它:

#node app.js

此时,应用启动起来,访问:http://localhost:3000 ,但是现在node 会占用命令行窗口,我们一旦关闭窗口,退出登录,服务将访问不了。所以说我们需要将它变为守护进程在后台悄悄的运行。

第一种(&):

上述的启动方式为‘前台任务’启动,它会占用命令行窗口,我们把它变为‘后台任务’

#node app.js &

我们在 命令 后面 加了 & ,它就会在后台任务执行,不会占用命令行窗口,我们也可以在前台任务 输入 ctrl+z ,让它暂停在后台,执行bg命令,恢复到前台执行。

后台任务继承当前session(对话)的标准输出(stdout)和标准错误(stderr),所以说,后台任务的所有输出依然会在冒命令行窗口输出。但是它不再继承标准输入(stdin),即我们不能向这个任务输入指令了。

上述方法,服务在‘后台任务’运行之后,它是否就是一个守护进程呢?此时我们退出登录,它是否依然在运行?

linux系统退出机制:

  1. 用户准备退出 session
  2. 系统向该 session 发出SIGHUP信号
  3. session 将SIGHUP信号发给所有子进程
  4. 子进程收到SIGHUP信号后,自动退出

‘后台任务’是否会收到 SIGHUP信号 是由shellhuponexit 参数决定的,我们来查看一下:

#shopt | grep huponexit

一般参数默认是 off ,此时退出时,不会把SIGHUP 信号发送给后台任务,后台任务不会随着退出登录而退出。

通过后台任务启动‘守护进程’并不保险,因为有的电脑可能会打开此参数(on),更稳妥的方式通过 disown 命令,它可以将指定的任务从‘后台任务’列表移除(通过jobs 查看后台任务列表)。如果不在‘后台任务’列表,session就不会向它发出SIGHUP信号。

#node app.js &
#disown

执行上面命令,app.js进程就被移除‘后台任务’列表,通过jobs 不会看到此运行进程。

disown 相关用法:

移出最近一个正在执行的后台任务
# disown

移出所有正在执行的后台任务
# disown -r

移出所有后台任务
# disown -a

不移出后台任务,但是让它们不会收到SIGHUP信号
# disown -h

根据jobId,移出指定的后台任务
# disown %2
# disown -h %2

使用disown命令之后,还有一个问题,就是后台进程与标准I/O有交互时,它还是会挂掉,比如我们在app.js 中添加一行代码:

app.on('request',(req,res)=>{

    console.log('is running')// 新添加的代码   

   res.setHeader('Content-Type','text/html;charset=utf8')

   res.end('hello world')
})

我们按照上面的流程再执行一次,发现服务并不能访问,因为后台任务的标准I/O继承当前的session,disown 并未改变这一点,一旦后台任务 发生读写I/O,就会发现它已经不存在了,所以会终止报错。我们可以最后台任务的标准I/O重定向解决这个问题。

# node app.js > stdout.txt  2>&1  &
# disown

第二种(nohup命令):

我们通过nohup更简单直接:

#nohub node app.js &

nohup 不会将任务放置后台,需要在命令最后加 &

nohup执行流程:

  • 阻止SIGHUP信号发到这个进程。
  • 关闭标准输入。该进程不再能够接收任何输入,即使运行在前台。
  • 重定向标准输出和标准错误到文件nohup.out。

第三种(Screen 命令与 Tmux 命令):

这两个命令的思路是终端复用器:在同一终端管理多个session

它们可以在当前 session 里面,新建另一个 session。这样的话,当前 session 一旦结束,不影响其他 session。而且,以后重新登录,还可以再连上早先新建的 session

Screen 的用法如下:

#screen      //新建一个session
#node app.js

然后,按下ctrl + Actrl + D,回到原来的 session,从那里退出登录。下次登录时,再切回去:

#screen -r

如果新建多个session,需要为它们指定名字:

# screen -S name
//切回指定 session
# screen -r name
# screen -r pid_number

//列出所有 session
# screen -ls

如果要停掉某个session,可以先切回它,然后ctrl+cctrl+d

Tmux命令使用如下:

# tmux
# node app.js

//返回原来的session
# tmux detach

除了tmux detach,另一种方法是按下Ctrl + Bd ,也可以回到原来的 session。

//下次登录时,返回后台正在运行服务session
# tmux attach

如果需要新建多个session,需要为每个session指定名字:

//新建 session
# tmux new -s session_name

//切换到指定 session
# tmux attach -t session_name

//列出所有 session
# tmux list-sessions

//退出当前 session,返回前一个 session 
# tmux detach

//杀死指定 session
# tmux kill-session -t session-name

第四种(node中相关包):

node中有不少相关管理进程的包:foreverpm2

forever使用:

//全局安装forever
#npm install forever -g

//作为前台任务启动
# forever server.js

//Start SCRIPT as a daemon
# forever start app.js

//Stop the daemon SCRIPT by Id|Uid|Pid|Index|Script
# forever stop Id

//重启服务进程
$ forever restart Id

//监视当前目录的文件变动,一有变动就重启
$ forever -w app.js

//-m 参数指定最多重启次数
$ forever -m 5 app.js 

//列出所有运行进程
# forever list

//相关参数:

-l  LOGFILE      Logs the forever output to LOGFILE
-o  OUTFILE      Logs stdout from child script to OUTFILE
-e  ERRFILE      Logs stderr from child script to ERRFILE

pm2使用:参考官方文档:http://pm2.keymetrics.io/docs/usage/quick-start/

相关参考资料:

https://github.com/foreverjs/forever#readme

[http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注