簡體   English   中英

僅當 cron 作業尚未運行時才運行它

[英]Run cron job only if it isn't already running

我正在嘗試將 cron 作業設置為我創建的守護進程的一種看門狗。 如果守護程序出錯並失敗,我希望 cron 作業定期重新啟動它......我不確定這有多大可能,但我閱讀了幾個 cron 教程,但找不到任何可以做我想做的事情我在找...

我的守護進程是從 shell 腳本啟動的,所以我真的只是在尋找一種方法來運行 cron 作業,前提是該作業的上一次運行尚未運行。

我找到了這篇文章,它確實為我嘗試使用鎖定文件做的事情提供了解決方案,但我不確定是否有更好的方法來做到這一點......

使用flock 這是新的。 更好。

現在您不必自己編寫代碼。 在此處查看更多原因: https : //serverfault.com/a/82863

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

我為我編寫的打印假脫機程序執行此操作,它只是一個 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 文件是一個很好的解決方案。 這是我的 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-one 我已經解決了我的問題。

 apt-get install run-one

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

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

看看這個askubuntu SE 答案。 您也可以在那里找到詳細信息的鏈接。

不要嘗試通過 cron 來實現。 無論如何,讓 cron 運行一個腳本,然后讓腳本決定程序是否正在運行並在必要時啟動它(請注意,您可以使用 Ruby 或 Python 或您喜歡的腳本語言來執行此操作)

您也可以直接在 crontab 中將其作為單行:

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

我在運行 php 腳本時這樣做的方式是:

定時任務:

* * * * * 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 代碼的開頭,它只會運行一次。

作為 Earlz 回答的后續,您需要一個包裝腳本,該腳本在開始時創建 $PID.running 文件,並在結束時刪除。 包裝器腳本調用您希望運行的腳本。 包裝器是必要的,以防目標腳本失敗或出錯,pid 文件被刪除..

使用lockrun您無需為您的 cron 作業編寫包裝腳本。 http://www.unixwiz.net/tools/lockrun.html

我建議使用現有的工具,例如monit ,它將監視和自動重啟進程。 此處提供更多信息。 它應該在大多數發行版中很容易獲得。

# 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 

這個從來沒有讓我失望:

一個.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>

我建議將以下內容作為對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 的退出狀態。

簡單的自定義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'

文檔: https : //www.timkay.com/solo/

solo 是一個非常簡單的腳本(10 行),它可以防止程序一次運行多個副本。 使用 cron 可以確保作業在前一個作業完成之前不會運行。

例子

* * * * * solo -port=3801 ./job.pl blah blah

如果您打算走那條路,請考慮使用 pgrep(如果可用)而不是通過 grep 管道傳輸的 ps。 雖然,就個人而言,我從表單的腳本中獲得了很多好處

while(1){
  call script_that_must_run
  sleep 5
}

雖然這可能會失敗,並cron作業往往必不可少的東西的最佳方式。 只是另一種選擇。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM