我写的一个监控java进程的shell脚本结合Linux crontab实现服务宕机重启,并实现按场景自动停止定时任务的功能
本来遇到了很奇怪的坑,crontab定时任务执行的shell脚本和自己手动执行的shell脚本不一致。
在java进程已启动的情况下, crontab定时任务执行的脚本却总是找不到对应的pid。
试了好几种解决方法,结果还是不行。
全部命令都用绝对路径执行啊,环境导入啊之类的,都试了下,没有作用,后来自己用crontab里写的定时任务试了试,出现了很多很奇怪的东西
后来还是在 grep “进程名” 之前加了个grep java 才解决的
crontab的定时任务如下:
*/10 * * * * sudo /bin/bash /opt/rocket/bin/monitor.sh
shell脚本如下:
#!bin/bash # source ~/.bash_profile . /etc/profile LOG_FILE='/opt/rocket/bin/logs/monitor_sh.log' # 打印日志,传一个参数($1 日志体) function log() { local time=$(date "+%Y-%m-%d %H:%M:%S") echo "[$time] $0 : $1 " >> ${LOG_FILE} } # 用来搜进程指定进程对应的pid,没有就返回0 # $1 : 进程名 function checkProcess() { if [ -z $1 ]; then log "Input parameter is empty." return 0 fi pid=`ps -aux | grep "java" | grep "$1" | grep -v grep | awk '{print $2}'` echo $pid } declare -i pid #声明变量为整形 pName="rocket_" #要查看的进程名 pid=`checkProcess ${pName}` if [ $pid -eq 0 ] then log "No specified ${pName} service starts." /bin/bash /opt/rocket/bin/start.sh else log "The specified service ${pName} has been started, pid=${pid}." fi
都写了注释,应该可以说是很清晰了。
核心逻辑就是查询指定的进程id,若是有则无事发生,若是没有 则执行另一个启动脚本将服务启动。期间伴随日志打印到特定文件中。
定时任务则是每十分钟启动一次,这个cron表达式在SpringBoot的定时任务里也有实现,就不说了。
这样子定时任务运行起来其实是没有问题的,但是还不能满足需求。
试想这么一个场景:
刚刚关闭掉这个服务器,还在上传文件/部署/设置参数 的过程中,此时时间刚好到那个定时任务启动的时间了,他这定时任务又给你把服务给启动起来了,那岂不是很尴尬。
而且定时任务又不是想停就停,linux的定时任务要停只能执行 crontab -e 然后手动修改文件才可以。
这个时候我灵光一闪,既然定时任务停不了,那我让你执行命令无法成功不就完事了
于是我在启动服务的脚本和关闭服务的脚本中加入了如下代码:
# 启动 if [ -f "/opt/rocket/bin/monitor_stop.sh" ];then mv /opt/rocket/bin/monitor_stop.sh /opt/rocket/bin/monitor.sh fi # 关闭 if [ -f "/opt/rocket/bin/monitor.sh" ];then mv /opt/rocket/bin/monitor.sh /opt/rocket/bin/monitor_stop.sh fi
在我手动关闭服务器时,关闭脚本会将定时任务试图执行的moniter.sh 文件名字给改了,这时候定时任务无法找到对应脚本则无法执行相应命令。
然后在我手动启动时,再给他改回去,让定时任务可以找到对应脚本。
最终实现效果果然如我所料一般完美,要是服务宕机,自然不是我手动关闭的,那么由于文件名没有被修改掉所以定时任务可以定时执行检测脚本,之后服务就会被重启。
那在维护时我手动进行的服务停止则会带动定时任务的停止,不用担心他自个偷偷摸摸的启动了。
整体实现效果非常满意。