结束进程
有些程序可以自动结束,如果事件循环中没有其他待处理的工作,则 Node.js 进程将自行退出,退出码为 process.exitCode
或者 0,这种情况会触发 exit 事件,不会触发 signal 事件。
有些程序无法自动结束,例如 Node.js 启动 HTTP 服务器,则该进程一直在监听客户端的请求,无法自动结束。如果我们想要结束该进程,可以通过两种方式:调用 process.exit()
或者发送 signal 信号。
退出码
一个 Node.js 进程不管以什么方式结束,都会有一个退出码。在命令行终端可以通过 echo $?
来查看上一个退出进程的退出码。
- 0:正常退出
- 1:发生未捕获错误
- 5:V8 引擎执行错误
- 8:不正确的参数
- 128 + 信号值:接收到 signal 信号
process.exit()
调用 process.exit(code)
结束进程,任何仍在事件循环中排队的其他工作被丢弃,这意味着任何待处理的回调、任何仍在发送的网络请求、任何文件系统访问、或者正在写入 stdout 或 stderr 的进程,所有这些都将立即被非正常地终止。因此不推荐以这种方式结束进程。
如果没有指定退出码,则使用默认值 0
// 以下两种方式相同
process.exit()
process.exit(0)
可以通过 process.exitCode
指定退出码的默认值
process.exitCode = 1
// 以下两种方式相同
process.exit()
process.exit(1)
调用 process.exit()
会触发 exit 事件(不会触发 signal 事件),一旦所有 exit 监听器都运行完毕,则 Node.js 进程将终止
process.on('exit', code => {
console.log(`Exit with code ${code}`)
})
process.exit(1)
监听器函数必须只执行同步的操作
process.on('exit', code => {
setTimeout(() => {
// exit 监听器执行之后,Node.js 进程将终止,任何仍在事件循环中排队的其他工作被丢弃
// 以下代码不会执行
console.log('This will not run');
}, 0)
})
发送 signal 信号
- SIGINT
- SIGHUP
- SIGTERM 正常终止
- SIGKILL 立即终止,类似 process.exit()
发送信号
- 终端:
ctrl + C
发送 SIGINT 信号 - 终端:
kill -signal pid
- 代码:
process.kill(pid, signal)
调用 process.kill(pid, signal)
只是向指定的进程发送一个信号,就像在终端使用 kill -signal pid
指令发送信号一样。具体是否会结束该进程,还要看该进程的代码中的信号事件绑定的监听器是如何工作的。
在一个 Node.js 程序中可以向任意一个进程发送信号
// 向 pid 为 3227 的进程发送 SIGTERM 信号
process.kill(3227, 'SIGTERM')
也可以向当前代码所在的进程发送信号
// process.pid 为当前进程的 pid
process.kill(process.pid, 'SIGTERM')
信号事件
当 Node.js 进程接收到一个信号时,会触发信号事件
- 如果没有为某个信号指定监听器,当 Node.js 进程收到该信号的时候,使用默认的监听器。
- SIGTERM SIGINT SIGHUP 默认的监听器,会以代码128 + signal number 结束进程。
- SIGTERM SIGINT SIGHUP 绑定自定义的监听器,原有默认的行为会被移除 (Node.js 进程不会结束)。
- SIGKILL 不能绑定自定义的监听器,当 Node.js 进程接收到该信号会使得 Node.js无条件终止。
process.on('SIGTERM', () => {
// 当前进程接收到 SIGTERM 信号,会调用该监听器
// 由于监听器里面没有代码能够结束当前进程,所以当前进程不会结束
// 如果不指定 SIGTERM 信号的监听器,当前进程接收到 SIGTERM 信号,会调用默认的监听器
// 默认的监听器会结束当前进程,退出码为 128 + 15,其中 15 为 SIGTERM 的 signal number
// 默认的监听器不会触发 exit 事件
console.log('当前进程接收到 SIGTEM 信号')
})
kill -SIGTERM 2587
向一个无法自动结束的进程发送信号,不管是通过代码发送信号 process.kill(pid, signal)
,还是通过终端发送信号 kill -signal pid
,只会触发 signal 事件,不会触发 exit 事件,除非在绑定的信号监听器里面执行 process.exit()
退出进程。
process.on('SIGTERM', () => {
console.log('当前进程接收到 SIGTEM 信号')
// 以下命令会触发 exit 事件
process.exit(0)
})
process.on('exit', (code) => {
console.log(`Exit with code ${code}`)
})
kill -SIGTERM 2587
网友评论