首页 文章

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

提问于
浏览
102

所以我试图 Build 一个cron作业作为我创建的守护进程的监视器 . 如果守护进程出错并失败,我希望cron作业定期重启...我不确定这是多么可能,但我通读了几个cron教程,找不到任何可以做到的东西我我正在寻找......

我的守护进程是从shell脚本启动的,所以我真的只是在寻找一种方法来运行一个cron作业,如果该作业的上一次运行还没有运行的话 .

I found this post,确实提供了一个解决方案,我不确定是否有更好的方法来做到这一点......

谢谢你的帮助 .

15 回答

  • 4

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

    apt-get install run-one
    

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

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

    查看this askubuntu SE回答 . 您也可以在那里找到详细信息的链接 .

  • 10

    您也可以直接在crontab中以单行方式执行此操作:

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

    作为Earlz回答的后续内容,您需要一个包装器脚本,它在启动时创建$ PID.running文件,并在结束时删除 . 包装器脚本调用您希望运行的脚本 . 如果目标脚本失败或错误输出,则必须使用包装器,pid文件将被删除 .

  • 1

    正如其他人所说,编写和检查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}"
    
  • 3

    不要试图通过cron来做 . 让cron运行一个脚本,无论如何,然后让脚本决定程序是否正在运行并在必要时启动它(请注意,您可以使用Ruby或Python或您喜欢的脚本语言来执行此操作)

  • 81

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

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

  • 18

    使用 flock . 它好了.2688902_更好 .

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

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

    我在运行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代码的开头,它将只运行一次 .

  • 0

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

  • 5

    使用 lockrun ,您无需为cron作业编写包装脚本 . http://www.unixwiz.net/tools/lockrun.html

  • 104

    This one从未失败过我:

    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 job

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

    我建议以下作为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的退出状态 .

  • 1

    简单的自定义php足以实现 . 无需与shell脚本混淆 .

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

    然后使用以下自定义php脚本执行相同的工作 .

    创建以下 /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'
    
  • 2
    # 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
    }
    
  • 22

    如果你要去那条路线,考虑使用pgrep(如果可用)而不是通过grep传输 . 虽然,就个人而言,我已经从表格的脚本中获得了很多

    while(1){
      call script_that_must_run
      sleep 5
    }
    

    虽然这可能会失败,而cron工作通常是必不可少的工作的最佳方式 . 只是另一种选择 .

相关问题