仅当 cron 任务尚未运行时才运行
- 2024-11-06 08:34:00
- admin 原创
- 30
问题描述:
我正在尝试设置一个 cron 作业作为我创建的守护进程的看门狗。如果守护进程出错并失败,我希望 cron 作业定期重新启动它...我不确定这有多大可能,但我读过几个 cron 教程,找不到任何可以满足我要求的东西...
我的守护进程是从 shell 脚本启动的,所以我实际上只是在寻找一种方法来运行 cron 作业,仅当该作业的上一次运行尚未运行时。
我发现这篇文章确实为我尝试使用锁文件执行的操作提供了解决方案,但我不确定是否有更好的方法来做到这一点......
解决方案 1:
使用flock
。它是新的。它更好。
现在您不必自己编写代码。在此处查看更多原因: https: //serverfault.com/a/82863
/usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script
解决方案 2:
我为自己编写的打印后台处理程序执行了此操作,它只是一个 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
它每两分钟运行一次,非常有效。如果由于某种原因进程没有运行,我会让它通过电子邮件向我发送特殊信息。
解决方案 3:
正如其他人所说,编写和检查 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:
令人惊讶的是没有人提到run-one。我已经用这个解决了我的问题。
apt-get install run-one
run-one
然后在 crontab 脚本前添加
*/20 * * * * * run-one python /script/to/run/awesome.py
查看这个askubuntu SE 答案。您也可以在那里找到详细信息的链接。
解决方案 5:
不要尝试通过 cron 来执行此操作。无论如何,让 cron 运行一个脚本,然后让脚本决定程序是否正在运行,并在必要时启动它(请注意,您可以使用 Ruby 或 Python 或您最喜欢的脚本语言来执行此操作)
解决方案 6:
我在运行 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)将大于一,因为搜索命令本身包含文件名
因此如果您运行 php cron,请将上述代码添加到 php 代码的开头,它将只运行一次。
解决方案 7:
您也可以直接在 crontab 中将其作为一行程序执行:
* * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>
解决方案 8:
作为对 Earlz 回答的后续,您需要一个包装器脚本,该脚本在启动时创建一个 $PID.running 文件,并在结束时删除。包装器脚本调用您想要运行的脚本。包装器是必需的,以防目标脚本失败或出错,pid 文件会被删除。
解决方案 9:
您lockrun
不需要为您的 cron 作业编写包装脚本。http ://www.unixwiz.net/tools/lockrun.html
解决方案 10:
# 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
}
更新..使用flock的更好方法:
/usr/bin/flock -n /tmp/your-app.lock /path/your-app args
解决方案 11:
我建议使用现有的工具,例如monit ,它将监视并自动重启进程。这里有更多信息。它应该在大多数发行版中都很容易获得。
解决方案 12:
这个从来没有让我失望过:
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}
计划任务:
* * * * * /path/to/one.sh <command>
解决方案 13:
文档:https://github.com/timkay/solo
solo 是一个非常简单的脚本(10 行),可防止程序一次运行多个副本。它与 cron 一起使用可确保在前一个作业完成之前不会运行下一个作业。
例子
* * * * * solo -port=3801 ./job.pl blah blah
解决方案 14:
我建议对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 的退出状态。
解决方案 15:
简单的自定义 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'
解决方案 16:
如果你要走这条路,请考虑使用 pgrep(如果可用)而不是通过 grep 管道传输的 ps。不过,就我个人而言,我从以下形式的脚本中获得了很大的收益
while(1){
call script_that_must_run
sleep 5
}
虽然这可能会失败,但 cron 任务通常是处理重要事务的最佳方式。这只是另一种选择。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件