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

Lor*_*nVS 117 linux bash cron watchdog

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

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

我找到了这篇文章,它确实提供了我正在尝试使用锁文件做的解决方案,而不是我不确定是否有更好的方法来做...

谢谢你的帮助.

jjc*_*son 113

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

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

  • 这个轮子已经在其他地方发明了:)例如,http://serverfault.com/a/82863/108394 (11认同)
  • 而不是`grep -v grep | 你可以做grep [d] octype.php`. (4认同)
  • 但是,不是一个非常安全的解决方案,如果有其他进程与您在grep中执行的搜索相匹配怎么办?rsanden的答案使用pidfile防止了这种问题. (3认同)

Jes*_*ess 101

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

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

/usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script
Run Code Online (Sandbox Code Playgroud)

  • 最好的解决方案,我已经使用了很长时间了. (3认同)
  • 我觉得这应该是公认的答案。很简单! (3认同)
  • 在非阻塞模式下的setlock,s6-setlock,chpst和runlock是不仅仅在Linux上可用的替代方案。https://unix.stackexchange.com/a/475580/5132 (2认同)

rsa*_*den 59

正如其他人所说,编写和检查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}"
Run Code Online (Sandbox Code Playgroud)

  • @Hamzahfrq:下面是它如何工作的:脚本首先检查是否PID文件存在("`[-e'$ {} PIDFILE’]`"如果没有,那么它会在后台启动该程序,将其PID写入文件("echo $!>"$ {PIDFILE}"`"),并退出.如果PID文件确实存在,则脚本将检查您自己的进程("`ps -u $( whoami)-opid =`")看看你是否正在使用相同的PID运行("`grep -P"^\s*$(cat $ {PIDFILE})$"`").如果你不是,然后它将像以前一样启动程序,用新的PID覆盖PID文件,然后退出.我认为没有理由修改脚本;是吗? (4认同)
  • +1使用pidfile它可能比使用相同名称的正在运行的程序的grepping更安全. (3认同)

Bed*_*mez 23

令人惊讶的是,没有人提到过第一次运行.我用这个解决了我的问题.

 apt-get install run-one
Run Code Online (Sandbox Code Playgroud)

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

*/20 * * * * * run-one python /script/to/run/awesome.py
Run Code Online (Sandbox Code Playgroud)

看看这个 askubuntu SE答案.您也可以在那里找到详细信息的链接.

  • 值得一提的是,*这个工具在 Ubuntu* 20 中是开箱即用的(也许之前的版本也是如此) (2认同)

Ear*_*rlz 22

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

  • 经典的方法是读取服务启动时创建的PID文件,检查具有该PID的进程是否仍在运行,如果没有则重新启动. (5认同)

小智 10

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

* * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>
Run Code Online (Sandbox Code Playgroud)

  • 不是很安全,如果有其他命令匹配搜索grep怎么办? (5认同)
  • 这太可怕了。`[ $(grep something | wc -l) -eq 0 ]` 是一种非常迂回的书写方式`! grep -q 的东西`。所以你只需要`ps -ef | grep '[c] 命令' || 命令` (3认同)

tal*_*ony 7

我在运行 php 脚本时这样做的方式是:

定时任务:

* * * * * php /path/to/php/script.php &
Run Code Online (Sandbox Code Playgroud)

php代码:

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

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

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


Byr*_*ock 5

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


Aar*_*uyn 5

有了它,lockrun您无需为您的 cron 作业编写包装脚本。 http://www.unixwiz.net/tools/lockrun.html