代码之家  ›  专栏  ›  技术社区  ›  LorenVS

仅当cron作业尚未运行时才运行它

  •  101
  • LorenVS  · 技术社区  · 15 年前

    所以我正试图设置一个cron作业作为我创建的守护进程的一种看门狗。如果守护进程出错并失败,我希望cron作业定期重新启动它…我不确定这有多可能,但我读了一些cron教程,找不到任何可以做我正在寻找的事情…

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

    I found this post ,这确实为我使用锁文件所做的工作提供了解决方案,但我不确定是否有更好的方法…

    谢谢你的帮助。

    15 回复  |  直到 8 年前
        1
  •  103
  •   jjclarkson Andy Rose    15 年前

    我为我编写的后台打印程序执行此操作,它只是一个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
    

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

        2
  •  79
  •   Community CDub    8 年前

    使用 flock . 这是新的。更好。

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

    /usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script
    
        3
  •  57
  •   rsanden Robert Dodier    10 年前

    正如其他人所说,编写和检查PID文件是一个很好的解决方案。下面是我的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}"
    
        4
  •  22
  •   Earlz    15 年前

    不要试图通过cron来实现。让cron运行一个脚本,不管是什么,然后让脚本决定程序是否在运行,并在必要时启动它(注意,您可以使用ruby或python或您最喜欢的脚本语言来执行此操作)。

        5
  •  17
  •   Community CDub    8 年前

    令人吃惊的是没人提到 run-one . 我用这个解决了我的问题。

     apt-get install run-one
    

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

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

    退房 this 阿斯库本图回答。你也可以在那里找到详细信息的链接。

        6
  •  10
  •   quezacoatl    12 年前

    您也可以直接在crontab中作为一个一行程序执行此操作:

    * * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>
    
        7
  •  5
  •   Byron Whitlock    15 年前

    作为对earlz答案的后续操作,您需要一个包装脚本,它在启动时创建一个$pid.running文件,在结束时删除。包装器脚本调用要运行的脚本。如果目标脚本失败或出错,则需要包装器,PID文件将被删除。

        8
  •  4
  •   talsibony    8 年前

    当我运行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
    

    此命令正在系统进程列表中搜索当前的PHP文件名 如果它存在,行计数器(wc-l)将大于1,因为搜索命令本身包含文件名

    因此,如果运行php crons,请将上述代码添加到php代码的开头,它将只运行一次。

        9
  •  3
  •   Zitrax dudico    15 年前

    我建议使用现有的工具,如 monit ,它将监视和自动重新启动进程。有更多信息可用 here . 它在大多数发行版中应该很容易获得。

        10
  •  3
  •   Aaron C. de Bruyn    10 年前

    lockrun 您不需要为cron作业编写包装脚本。 http://www.unixwiz.net/tools/lockrun.html

        11
  •  2
  •   DJV    8 年前

    This one 我从未失败过:

    在某地 :

    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}
    

    定时任务 :

    * * * * * /path/to/one.sh <command>
    
        12
  •  1
  •   Community CDub    7 年前

    我建议你改进一下 rsanden's answer (我会发表评论,但没有足够的声誉…):

    #!/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的退出状态。

        13
  •  1
  •   lingeshram    9 年前

    简单的自定义PHP就足够了。无需与shell脚本混淆。

    假设你想跑 php/home/mypath/example.php 如果不运行

    然后使用下面的自定义PHP脚本来完成相同的工作。

    创建以下内容 /主页/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'
    
        14
  •  1
  •   ekerner    8 年前
    # 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
    }
    
        15
  •  0
  •   Richard Thomas    12 年前

    考虑使用pgrep(如果可用),而不是通过grep导入的ps,如果您要走这条路。不过,就我个人而言,我有很多工作要做

    while(1){
      call script_that_must_run
      sleep 5
    }
    

    尽管这可能会失败和cron作业 通常是必备品的最佳选择。只是另一种选择。