@Kosha_not
Быдлокодер

Как запретить одновременный запуск PHP скрипта по крону?

Добрый день, появился вот такой вопрос и никак не могу найти универсального и простого решения. Может кто-нибудь помочь разобраться в теме?

Есть php скрипт, который будет запускаться по крону каждую минуту. Так как скрипт может выполниться то за 5 секунду, то за полчаса, то задача стоит такая - если прошлый запуск еще не завершился, то новый не запускать, чтобы не мешали друг другу и не делали одну работу.

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

Вспомнил про flock. Накидал для проверки вот такой вариант:
$lockfile = fopen("my_script.lock", 'w');
if(flock($lockfile, LOCK_EX | LOCK_NB ) !== true)
	die("already running");
echo 'Good';
flush();
sleep(10);


Запускаю через браузер 1-ый раз скрипт - пошел в работу, во второй вкладке запускаю его еще раз и вместо ожидаемого "already running" вижу, что скрипт встал в очередь и ждет пока завершится предыдущий, после завершения 1-го, отрабатывает 2-ой.

Искал другие варианты реализации на flock - результаты аналогичные, второй запуск скрипта приводит к ожиданию завершения первого.

Мне такой вариант не подходит, так как я не понимаю, что произойдет, если скрипт будет выполняться, например за 3 минуты, а вызываться по крону будет каждую минуту - сформируется длинная очередь ожидающих?

Подскажите, пожалуйста, какое-нибудь максимально универсальное решение.
  • Вопрос задан
  • 2132 просмотра
Решения вопроса 1
DevMan
@DevMan
$lock = fopen('/tmp/lock_file.lock', 'w');
if ( !($lock && flock($lock, LOCK_EX | LOCK_NB)) ) {
    exit( 'already running' );
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
maximw
@maximw
Если в скрипте уже используется коннект к Mysql, можно еще использовать его реализацию семафора, не "загрязняя" файловую систему.
Посмотрите на функцию: GET_LOCK()
Этот метод лишен недостатка, описанного вами. При "умирании" процесса который сделал лок, лок освобождается автоматически.

P,S, Если уж используете файлы, посмотрите register_shutdown_function(), где можно аварийно удалять лок-файл.
Ответ написан
@entermix
$fh = fopen(__FILE__, 'r');
        if (!flock($fh, LOCK_EX | LOCK_NB)) {
            die('Script is already running!');
        }
Ответ написан
Комментировать
@ShamblerR
лок есть в самом кроне
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы