重启服务时 kill 了启动脚本的 PID,java 进程还在跑,8080 端口一直占用,新实例起不来报 Address already in use,只能手动 kill -9。第一次遇到会往复杂处想,其实漏掉的多是个小前提。
trap 'kill -TERM "$PID"; wait "$PID"' TERM INT java -jar app.jar & PID=$! wait "$PID"
启动脚本用后台方式拉起子进程,没有把信号转发下去,也没有注册 trap。父进程退出,子进程被 init 接管继续运行。这一点先确认清楚,后面就不用反复试。
「信号处理缺失」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。
动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。
具体做法是,用 trap 捕获 TERM 和 INT 转给子进程再退出;记录子进程 PID 停止时按 PID 精确 kill;用 exec 让子进程替换父进程 信号直接送达;重启一次 确认端口能立刻释放。
改完照着核一遍,kill 脚本后 java 进程同时退出,8080 端口在 5 秒内释放。
