Запустить задание cron, только если оно еще не запущено

поэтому я пытаюсь настроить работу cron как своего рода сторожевого пса для демона, которого я создал. Если демон ошибается и терпит неудачу, я хочу, чтобы задание cron периодически перезапускалось... Я не уверен, насколько это возможно, но я прочитал пару учебников cron и не смог найти ничего, что сделало бы то, что я ищу...

мой демон запускается из сценария оболочки, поэтому я действительно просто ищу способ запустить задание cron, только если предыдущий запуск этого задания еще не завершен бегущий.

я нашел этот пост, который предоставил решение для того, что я пытаюсь сделать с помощью файлов блокировки, не я не уверен, есть ли лучший способ сделать это...

Спасибо за помощь.

15 ответов


Я делаю это для программы диспетчера очереди печати, которую я написал, это просто сценарий оболочки:

#!/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

он работает каждые две минуты и довольно эффективен. У меня есть электронная почта со специальной информацией, если по какой-то причине процесс не работает.


использовать flock. Он новый. Так лучше.

теперь вам не нужно писать код самостоятельно. Проверьте больше причин здесь:https://serverfault.com/a/82863

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

Как заявили другие, написание и проверка 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}"

Не пытайтесь сделать это через cron. Пусть cron запускает сценарий независимо от того, что, а затем сценарий решает, работает ли программа, и запускает ее, если это необходимо (обратите внимание, что вы можете использовать Ruby или Python или ваш любимый язык сценариев для этого)


удивительно, что никто не упомянул о run-one. Я решил свою проблему с этим.

 apt-get install run-one

затем добавить run-one перед вашим скриптом crontab

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

проверить этой askubuntu SE ответ. Вы также можете найти ссылку на подробную информацию.


вы также можете сделать это как однострочный непосредственно в crontab:

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

в качестве продолжения ответа Earlz вам нужен сценарий оболочки, который создает $PID.запуск файла при его запуске и удаление при его завершении. Скрипт вызывается скрипт, который вы хотите запустить. Оболочка необходима в случае сбоя или ошибки целевого сценария, PID-файл удаляется..


способ, которым я это делаю, когда я запускаю 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 crons, добавьте приведенный выше код в начало вашего php-кода, и он будет работать только один раз.


С lockrun вам не нужно писать сценарий оболочки для вашей работы cron. http://www.unixwiz.net/tools/lockrun.html


Я бы рекомендовал использовать существующий инструмент, такой как монит, он будет контролировать и процессов, автоматический перезапуск. Существует более подробная информация здесь. Он должен быть легко доступен в большинстве дистрибутивов.


этот никогда меня не подводил:

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-задание:

* * * * * /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 script.

предположим, вы хотите запустить php / home/mypath / пример.в PHP если не работает

затем использовать следующий пользовательский PHP-скрипт для выполнения той же работы.

создать следующее / главная / mypath / навсегда.в 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'

# one instance only (works unless your cmd has 'grep' in it)
ALREADY_RUNNING_EXIT_STATUS=0
bn=`basename `
proc=`ps -ef | grep -v grep | grep "$bn" | grep -v " $$ "`
[ $? -eq 0 ] && {
    pid=`echo $proc | awk '{print }'`
    echo "$bn already running with pid $pid"
    exit $ALREADY_RUNNING_EXIT_STATUS
}

рассмотрите возможность использования pgrep (если доступно), а не ps через grep, если вы собираетесь идти по этому маршруту. Хотя, лично у меня есть много пробега из скриптов формы

while(1){
  call script_that_must_run
  sleep 5
}

хотя это может потерпеть неудачу и задания cron are часто лучший способ для необходимых вещей. Еще одна альтернатива.