У меня есть скрипт php-cli
который запускается cron
каждые 5 minutes
. Поскольку этот интервал является коротким, multiple processes
выполняются multiple processes
. Это не то, что я хочу, так как этот скрипт должен писать внутри текстового файла числовой id
который увеличивается каждый раз. Бывает, что writers
пишут в этом текстовом файле, а записанное значение неверно.
Я попытался использовать функцию php flock
чтобы заблокировать запись в файле, когда на него записывается другой процесс, но он не работает.
$fw = fopen($path, 'r+');
if (flock($fw, LOCK_EX)) {
ftruncate($fw, 0);
fwrite($fw, $latestid);
fflush($fw);
flock($fw, LOCK_UN);
}
fclose($fw);
Поэтому я полагаю, что решение этого - создать сценарий bash
который проверяет, есть ли экземпляр этого PHP скрипт
который работает, если так, то он должен ждать, пока он не закончится. Но я не знаю, как это сделать, какие-то идеи?
Решение, которое я использую с помощью bash script
таково:
exec 9>/path/to/lock/file
if ! flock -n 9 ; then
echo "another instance is running";
exit 1
fi
# this now runs under the lock until 9 is closed (it will be closed automatically when the script ends)
В файле /var/lock/file
создается файловый дескриптор 9>
, и flock
завершит выполнение нового процесса, который будет запущен, если нет другого экземпляра скрипта, который работает.
Я действительно не понимаю, как увеличение счетчика каждые 5 минут приведет к нескольким процессам, которые пытаются написать файл счетчика одновременно, но...
Гораздо проще использовать простой механизм блокировки, подобный приведенному ниже:
<?php
$lock_filename = 'nobodyshouldincrementthecounterwhenthisfileishere';
if(file_exists($lock_filename)) {
return;
}
touch($lock_filename);
// your stuff...
unlink($lock_filename);
Это как простой подход не будет иметь дело с ситуацией, когда сценарий ломается, прежде чем он сможет удалить файл блокировки, и в этом случае он никогда не будет запускаться снова до его удаления.
Более сложные подходы также возможны, как вы предлагаете, например, fork job в своем собственном процессе, записывать PID в файл, а затем перед запуском задания можно проверить, продолжает ли этот PID.
return
когда файл блокировки существует, идеальным способом будет держать его в цикле, который sleep
в течение секунды или около того, а затем перепроверяет блокировку. файл.
Чтобы предотвратить запуск следующего сеанса любой программы до тех пор, пока предыдущий сеанс не будет запущен, например следующее задание cron, я рекомендую использовать встроенную в вашу программу или внешнюю проверку запуска этой программы. Просто выполните перед запуском вашей программы
ps -ef|grep <process_name>|grep -v grep|wc -l
и проверьте, будет ли его результат равен 0. Только в этом случае ваша программа может быть запущена. Я полагаю, что вы должны гарантировать отсутствие стороннего процесса с похожим именем. (Для этого дайте вашей программе более длинное и уникальное имя). И имя вашей программы не должно содержать шаблон "grep".
Эта работа хороша в сочетании с обычным регулярным запуском вашей программы, которая настроена в таблице cron с помощью демона cron. В случае, если ваш чек написан как внешний скрипт, запись в crontab может выглядеть так:
<time_specification> <your_starter_script> <your_program> ...
2 важных замечания: код выхода вашего_starter_script должен быть 0 в случае не запуска вашей программы, и было бы лучше полностью запретить запись в stdout или stderr с помощью этого скрипта.
Такой стартер очень короткий и простое программирование. Поэтому я не чувствую необходимости предоставлять полный код.
Или, может быть, даже проще, чем мой предыдущий ответ (используя at
запланировать сценарий снова запустить в течение 5 минут), это сделать ваш сценарий демона, используя не-завершающий цикл, например, так:
while(1) {
// whatever your script does here....
sleep(300) //wait 5 minutes
}
Затем, вы можете избавиться от планирования путем cron
или at
целом. Просто запустите свой сценарий в фоновом режиме из командной строки, например:
/path/to/your/script &
Или добавьте /path/to/your/script
в /etc/rc.local, чтобы ваш скрипт запускался автоматически при загрузке машины.
Вместо того, чтобы использовать cron
для запуска сценария каждых 5 минут, как об использовании at
запланировать сценарий для повторного запуска, через 5 минут после его завершения. В конце вашего сценария вы можете использовать shell_exec() для запуска команды at
чтобы запланировать запуск скрипта за 5 минут, например:
at now + 5 minutes /path/to/script