共享一个防止脚本重复启动的shell脚本

项目的一个需求:为防止脚本重复调度,导致同时运行时相互冲突,需要在脚本运行开始前创建一个文件,结束时删除。

脚本启动时判断一下文件是否存在,如果存在则退出。

最开始这样做没发现问题,但跑一段时间后,发现如果进程中间退出没删除文件就会出现问题。

而且有时希望等待一段时间后不管有没有已启动同名脚本,都往下走。

基于以上考虑,最近将这个防止重复启动的逻辑抽离出来成为独立脚本,并增加了一些控制逻辑,这样以后需要类似功能直接调用这个脚本就好。

 

流程图:

 

 

 

 

 

 

代码:

 

#! /bin/sh
# singleton.sh 进程名($0) 进程id($$) 工作目录 休眠时间 尝试次数
# 尝试次数为0代表无限次
# 本脚本的作用是防止进程重复启动(类似单例) 脚本启动后会在工作目录生成一个进程信息文件(pidfile)起到唯一锁作用
# 如果pidfile里面的进程不存在 脚本就会结束 否则会一直等待直到尝试次数超限

if [ $# != 5 ]
then
    echo "usage:singleton.sh 进程名(\$0) 进程id(\$\$) 工作目录 休眠时间 尝试次数(0代表无限次)"
    exit 1
fi

v_proc_name=${1##*/}
v_pid=$2
v_work_dir=$3
v_sleep_seconds=$4
v_retry_times=$5
# pid文件路径 模拟文件锁用的
v_pid_file=${v_work_dir}/singleton_run_pid

echo "cmd = $0 $*"

# 判断pid文件是否存在
# 如存在判断文件里面的进程是否存在 且进程名字相同
# 如果符合以上条件则休眠后再次尝试 直至满足最大尝试次数
if [ -f ${v_pid_file} ]
then
    echo "file[${v_pid_file}] exists!"
    
    v_times=0
    v_max_retry_times=${v_retry_times}
    while [ ${v_times} -lt ${v_max_retry_times} -o ${v_retry_times} -eq 0 ]
    do
        v_pid_old="";v_proc_name_old="";
        read v_pid_old v_proc_name_old < ${v_pid_file}
        
        if [ "${v_pid_old}" = "" -o "${v_proc_name_old}" = "" ]
        then
            echo "error pidfile [$(cat ${v_pid_file})]"
            break;
        fi
        
        # 考虑到脚本有时被强制杀掉会导致pid文件残留没清理,这里加上对pid文件内容判断
        if [ ${v_proc_name_old} != ${v_proc_name} ]
        then
            echo "proc_name not euqal; [${v_proc_name_old}] != [${v_proc_name}]! do next;"
            break;
        fi
        
        if [ ${v_pid} = ${v_pid_old} ]
        then
            echo "pid euqal; [${v_pid}] = [${v_pid_old}]! do next;"
            break;
        fi
        
        # grep 参数 -- 代表参数结果 后面跟的是关键字或文件名 这是为了避免进程名是-bash的问题  
        v_pid_inf=$(ps -ef|awk -v v_pid_old=${v_pid_old} '{ if($2 == v_pid_old) print $0; }'|grep -w -- ${v_proc_name})
        if [ "${v_pid_inf}" = "" ]
        then
            echo "cannot find the pid[ps -ef|awk -v v_pid_old=${v_pid_old} '{ if(\$2 == v_pid_old) print \$0; }'|grep -w -- ${v_proc_name}]! do next;"
            break;
        fi
        
        v_times=$(expr ${v_times} + 1)
        echo "try times ${v_times}; sleep ${v_sleep_seconds}"
        sleep ${v_sleep_seconds}
    done
    
    echo "had tried ${v_times} times! do next;"
fi

echo "create file[${v_pid_file}]!"
echo ${v_pid} ${v_proc_name} > ${v_pid_file}

 

posted @ 2016-10-29 18:09  皇家救星  阅读(3262)  评论(1编辑  收藏  举报