У меня есть cronjob, который запускает PHP на файле wordpress cron.php. Он в основном используется для планирования постов и, как мне кажется, может обновлять кэш.
Я запускаю задание cron каждую минуту. Я часто проверял ps и вижу ДВА экземпляра PHP, запускающих cron.php. Теперь это не нужно, потому что запуск одного экземпляра сделает все, что нужно. У меня есть другое задание, которое проверяет оперативную память, и иногда два экземпляра отключают его (я ожидаю, что большой объем оперативной памяти будет доступен в любое время, я могу уменьшить его, но не хочу). Я с трудом верю, что одно задание может занять больше минуты (хотя это может быть).
Как мне запустить задание, но не если процесс уже существует? Я не думаю, что сам код PHP может проверить, если он не подключается/не использует базу данных? Есть ли команда cron, которую я могу использовать? Я не хочу убивать экземпляр, если он >1 минуты. Просто не создавать новые.
решение1
Вот простое решение на основе скрипта bash; вы, вероятно, можете сделать то же самое в скрипте cron.php. Он на самом деле проверяет процессы, которые выполняются слишком долго; для автоматизированной системы это, вероятно, хорошая идея.
#!/bin/bash
# Exit if process is already running
if test -e /tmp/wordpress-job.pid; then
# Check if the pid that was stored in /tmp/wordpress-job.pid does exist
if ps ax -o pid= | grep $(cat /tmp/wordpress-job.pid ) &> /dev/null; then
exit 0
fi
fi
# Create the file that marks this process as running
echo $$ > /tmp/wordpress-job.pid
# Some extra security check to prevent the pid file
# to survive.
trap "rm -f /tmp/wordpress-job.pid" EXIT TERM INT HUP
# Start the long-running process in the background
sleep 3600 & # long-running process
# Sleep some time before trying to kill that process
sleep 300
# Kill job if it takes longer than it should
kill %1
# Delete the file that marks this process as running
rm -f /tmp/wordpress-job.pid
Вам необходимо заменить «sleep 3600» на вашу командную строку php, а 300 ниже — на максимальное время, в течение которого может выполняться ваш скрипт.
решение2
Заставьте вашу запись crontab запустить это:
if mv /var/run/my-php-job.pending /var/run/my-php-job.running 2>/dev/null; then
echo $$ >|/var/run/my-php-job.running # optional
… # run the job
: >|/var/run/my-php-job.running # optional
mv /var/run/my-php-job.running /var/run/my-php-job.pending
fi
Поместите это в @reboot
запись crontab:
rm -f /var/run/my-php-job.running
touch /var/run/my-php-job.pending
Имя файла служит замком. Пока это .running
, есть запущенное задание, и следующее задание не запустится. Когда это .pending
, запущенное задание запускается и переключается на .running
.
Если вы включите необязательные строки, идентификатор процесса оболочки будет записан в .running
файл для целей расследования, если задание зависнет. Файл журнала сделает это в основном избыточным.
Если оболочка, выполняющая задание, аварийно завершается (что маловероятно и может произойти только в том случае, если кто-то намеренно завершит ее работу или в условиях нехватки памяти), файл блокировки застрянет на .running
. (Если само задание аварийно завершается, это не проблема.) Вы можете обнаружить внезапную смерть предыдущего скрипта, но это значительно сложнее.
решение3
Существуют специальные утилиты для избежания параллельных запусков: flock в util-linux, lockf в системах BSD, shlock в NetBSD, а также в пакетах INN и cnews.
В наиболее вероятном случае (Linux) вызовите что-то похожее на:
flock -w 60 /somedir/lockfile cron.php
Рецепты в других ответах являются альтернативой домашнему птицеводству и полезны только в случае отсутствия такого инструмента.
С другой стороны, вы можете справиться с такой блокировкой непосредственно в своей программе, но вам следует тщательно повторить все детали, иначе вы можете создать состояние гонки.