我们来编写一个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系统退出机制:
用户准备退出 session
系统向该 session 发出SIGHUP信号
session 将SIGHUP信号发给所有子进程
子进程收到SIGHUP信号后,自动退出
‘后台任务’是否会收到 SIGHUP信号 是由shell 的huponexit 参数决定的,我们来查看一下:
#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 + A和ctrl + D,回到原来的 session,从那里退出登录。下次登录时,再切回去:
#screen -r
如果新建多个session,需要为它们指定名字:
# screen -S name
//切回指定 session
# screen -r name
# screen -r pid_number
//列出所有 session
# screen -ls
如果要停掉某个session,可以先切回它,然后ctrl+c 和ctrl+d
Tmux命令使用如下:
# tmux
# node app.js
//返回原来的session
# tmux detach
除了tmux detach,另一种方法是按下Ctrl + B和 d ,也可以回到原来的 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中有不少相关管理进程的包:forever,pm2等
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
相关参考资料:
[http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html