Shell脚本中如何检测serve-prod进程PID 终止后进程仍运行问题排查
原脚本进程管理失效的核心原因
pgrep serve-prod抓PID逻辑完全不可靠- 启动后立刻执行pgrep时,npm进程可能还未完成命令解析、未派生真正的业务服务子进程,存在抓空、抓错的问题
- pgrep是按命令行字符串模糊匹配,可能匹配到系统中其他带相同字符串的无关进程,也可能只匹配到npm的包装父进程,抓不到真正监听9000端口的node子进程
pkill serve-prod终止逻辑存在漏杀- npm run启动的服务是嵌套进程树结构:npm包装进程 -> 实际node业务进程,当node进程的命令行不包含
serve-prod字符串时,pkill按字符串匹配的规则根本找不到这个子进程,只会杀掉npm的空壳父进程,子进程变成孤儿后被系统init进程接管,持续占用9000端口运行,出现“杀完进程还在”的异常
- npm run启动的服务是嵌套进程树结构:npm包装进程 -> 实际node业务进程,当node进程的命令行不包含
- 等待逻辑缺乏异常兜底
- 端口连通性检测的循环里没有校验web进程的存活状态,一旦服务启动崩溃,脚本会无限卡在等待逻辑里,不会主动退出
- 无进程组隔离存在误杀风险
- 直接后台启动的npm进程会和执行脚本的bash进程共享同一个进程组,后续按进程组终止时,很容易误杀脚本本身的运行进程
可靠的实现方案
- 放弃模糊匹配抓PID的逻辑,直接用Shell内置变量
$!捕获后台启动任务的精准父进程PID,该变量永远指向当前shell最近启动的后台任务PID,无匹配误差 - 用
setsid给web服务创建独立的进程组,让服务完全和当前脚本的进程环境隔离,从根源上避免终止时的误杀问题 - 采用进程组级别的终止逻辑:发送终止信号时指定进程组ID(在PID前加负号),可以一次性杀掉整个派生树的所有子进程,从根源上避免残留孤儿进程
- 给等待逻辑增加异常兜底:在端口连通性检测的循环里,增加对web进程存活状态的检测,一旦进程提前退出直接抛错退出脚本,避免无限等待
修正后完整可运行脚本
#!/bin/bash # 开启脚本严格模式,避免静默错误 set -euo pipefail # 用setsid给web服务创建独立进程组,与当前shell环境隔离 setsid npm run serve-prod & WEB_PID=$! echo "已捕获web服务关联父进程PID: $WEB_PID" echo "waiting for webserver" while ! nc -z localhost 9000; do # 检测web进程是否异常退出,提前中断等待逻辑 if ! kill -0 "$WEB_PID" 2>/dev/null; then echo "错误:web服务进程异常退出,启动失败" exit 1 fi sleep 1 done # 执行业务逻辑 npm run print-map # 终止整个web独立进程组,无漏杀、无误杀 kill -- -"$WEB_PID" echo "web服务已正常终止"
内容的提问来源于stack exchange,提问作者Petr Volny
相关产品推荐
相关产品推荐

