只有在没有运行的情况下才运行cron作业

所以我试图设置一个cron作为一个守护进程,作为我创build的一个守护进程。 如果守护进程错误,并失败,我希望cron作业定期重新启动它…我不知道这是多么可能,但我读了几个cron教程,并找不到任何事情,将做我所正在找…

我的守护进程从一个shell脚本开始,所以我真的只是寻找一种方法来运行一个cron工作只有当该作业的上一次运行还没有运行。

我发现这个post ,它提供了一个解决scheme,我正在尝试使用locking文件,而不是我不确定是否有更好的方法来做到这一点…

谢谢你的帮助。

我这样做是为了写一个打印后台处理程序,它只是一个shell脚本:

#!/bin/sh if ps -ef | grep -v grep | grep doctype.php ; then exit 0 else /home/user/bin/doctype.php >> /home/user/bin/spooler.log & #mailing program /home/user/bin/simplemail.php "Print spooler was not running... Restarted." exit 0 fi 

它每两分钟运行一次,非常有效。 如果由于某种原因,这个过程没有运行,我会通过电子邮件向我发送特殊信息。

正如其他人所说,编写和检查PID文件是一个很好的解决scheme。 这是我的bash实现:

 #!/bin/bash mkdir -p "$HOME/tmp" PIDFILE="$HOME/tmp/myprogram.pid" if [ -e "${PIDFILE}" ] && (ps -u $(whoami) -opid= | grep -P "^\s*$(cat ${PIDFILE})$" &> /dev/null); then echo "Already running." exit 99 fi /path/to/myprogram > $HOME/tmp/myprogram.log & echo $! > "${PIDFILE}" chmod 644 "${PIDFILE}" 

使用flock 。 这是新的。 好多了

现在你不必自己编写代码。 在这里查看更多的原因: https : //serverfault.com/a/82863

 /usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script 

不要试图通过cron来做到这一点。 让cron运行一个脚本,然后让脚本决定程序是否在运行,如果有必要的话启动它(注意你可以使用Ruby或者Python或者你最喜欢的脚本语言来做到这一点)

你也可以直接在你的crontab中作为一行代码来完成它:

 * * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command> 

令人惊讶的是,没有人提到关于跑步 。 我已经解决了我的问题。

  apt-get install run-one 

然后在您的crontab脚本之前添加run-one

 */20 * * * * * run-one python /script/to/run/awesome.py 

看看这个 askubuntu SE的答案。 您也可以在此find详细信息的链接。

作为Earlz回答的后续,您需要一个包装脚本,它在启动时创build一个$ PID.running文件,并在结束时删除。 包装脚本调用你想运行的脚本。 包装是必要的,如果目标脚本失败或错误,pid文件被删除..

我正在运行php脚本的方式是:

crontab:

 * * * * * php /path/to/php/script.php & 

php代码:

 <?php if (shell_exec('ps aux | grep ' . __FILE__ . ' | wc -l') > 1) { exit('already running...'); } // do stuff 

这个命令是在系统进程列表中search当前的php文件名,如果它存在的话,行计数器(wc -l)将大于1,因为search命令本身包含文件名

所以如果你运行php crons,将上面的代码添加到你的php代码的开始,它将只运行一次。

使用lockrun你不需要为你的cron作业编写一个包装脚本。 http://www.unixwiz.net/tools/lockrun.html

我会build议使用现有的工具,如监视,它会监视和自动重新启动进程。 这里有更多的信息。 它应该可以在大多数发行版中轻松使用。

我build议以下作为改善rsanden的答案 (我会发表评论,但没有足够的声誉…):

 #!/usr/bin/env bash PIDFILE="$HOME/tmp/myprogram.pid" if [ -e "${PIDFILE}" ] && (ps -p $(cat ${PIDFILE}) > /dev/null); then echo "Already running." exit 99 fi /path/to/myprogram 

这样可以避免可能的错误匹配(以及grepping的开销),并且它会抑制输出并仅依靠ps的退出状态。

这个从来没有让我失望:

one.sh

 LFILE=/tmp/one-`echo "$@" | md5sum | cut -d\ -f1`.pid if [ -e ${LFILE} ] && kill -0 `cat ${LFILE}`; then exit fi trap "rm -f ${LFILE}; exit" INT TERM EXIT echo $$ > ${LFILE} $@ rm -f ${LFILE} 

cron工作

 * * * * * /path/to/one.sh <command> 

考虑使用pgrep(如果有的话),而不是ps通过greppipe道,如果你要去那条路线。 虽然,个人而言,我从表格的脚本中获得了很多里程碑

 while(1){ call script_that_must_run sleep 5 } 

虽然这可能会失败,并且cron工作往往是最基本的东西的最佳途径。 只是另一种select。

简单的自定义php就足以实现。 不需要与shell脚本混淆。

让我们假设你想运行php /home/mypath/example.php,如果没有运行

然后使用下面的自定义PHP脚本来做同样的工作。

创build以下/home/mypath/forever.php

 <?php $cmd = $argv[1]; $grep = "ps -ef | grep '".$cmd."'"; exec($grep,$out); if(count($out)<5){ $cmd .= ' > /dev/null 2>/dev/null &'; exec($cmd,$out); print_r($out); } ?> 

然后在你的cron中添加以下内容

 * * * * * php /home/mypath/forever.php 'php /home/mypath/example.php' 
 # one instance only (works unless your cmd has 'grep' in it) ALREADY_RUNNING_EXIT_STATUS=0 bn=`basename $0` proc=`ps -ef | grep -v grep | grep "$bn" | grep -v " $$ "` [ $? -eq 0 ] && { pid=`echo $proc | awk '{print $2}'` echo "$bn already running with pid $pid" exit $ALREADY_RUNNING_EXIT_STATUS }