Запуск задания 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 job:
* * * * * /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-скрипт для выполнения той же работы.
создать следующее / home/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 часто лучший способ для необходимых вещей. Просто еще одна альтернатива.