Как предотвратить выполнение задания cron, если оно уже запущено

У меня есть один скрипт php, и я выполняю этот скрипт через cron каждые 10 минут на CentOS.

Проблема в том, что если задание cron займет более 10 минут, начнется другой экземпляр того же задания cron.

Я попробовал один трюк, то есть:

  1. Создал один файл блокировки с php-кодом (таким же, как файлы pid), когда началось задание cron.
  2. При завершении задания удаляется файл блокировки с помощью php-кода.
  3. И когда какое-либо новое задание cron запустило выполнение скрипта, я проверил, существует ли файл блокировки и если это так, прервал скрипт.

Но может быть одна проблема: когда файл блокировки не удаляется или не удаляется скриптом по какой-либо причине. Крон никогда не начнет снова.

Есть ли способ остановить выполнение задания cron снова, если он уже запущен, с командами Linux или подобными этому?

Консультативная блокировка выполняется именно для этой цели.

Вы можете выполнить консультативную блокировку с помощью flock() . Просто примените функцию к ранее открытому файлу блокировки, чтобы определить, есть ли у него другой скрипт.

 $f = fopen('lock', 'w') or die ('Cannot create lock file'); if (flock($f, LOCK_EX | LOCK_NB)) { // yay } 

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

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

Может быть, лучше не писать код, если вы можете его настроить:

https://serverfault.com/questions/82857/prevent-duplicate-cron-jobs-running

flock() отлично подходит для меня – у меня есть задание cron с запросами базы данных, которые планируются каждые 5 минут, поэтому не иметь нескольких запусков одновременно. Это то, что я сделал:

 $filehandle = fopen("lock.txt", "c+"); if (flock($filehandle, LOCK_EX | LOCK_NB)) { // code here to start the cron job flock($filehandle, LOCK_UN); // don't forget to release the lock } else { // throw an exception here to stop the next cron job } fclose($filehandle); 

Если вы не хотите убивать следующее запланированное задание cron, но просто приостанавливайте его до тех пор, пока он не будет завершен, просто опустите LOCK_NB :

 if (flock($filehandle, LOCK_EX)) 

Это очень распространенная проблема с очень простым решением: cronjoblock простая 8-строчная оболочечная оболочка применяет блокировку с использованием стаи:

https://gist.github.com/coderofsalvation/1102e56d3d4dcbb1e36f

Кстати. cronjoblock также отменяет спам-спам электронной почты cron: только выводьте что-то, если что-то пойдет не так. Это удобно в отношении переменной MAILTO cron. Выход stdout / stderr будет подавлен (поэтому cron не будет отправлять почту), если у данного процесса нет кода выхода> 0

flock не будет работать в php 5.3.3, поскольку была удалена автоматическая разблокировка, когда дескриптор ресурса файла был закрыт. Разблокирование теперь всегда должно выполняться вручную.

Я использую это ::

 <?php // Create a PID file if (is_file (dirname ($_SERVER['SCRIPT_NAME']) . "/.processing")) { die (); } file_put_contents (dirname ($_SERVER['SCRIPT_NAME']) . "/.processing", "processing"); // SCRIPT CONTENTS GOES HERE // @unlink (dirname ($_SERVER['SCRIPT_NAME']) . "/.processing"); ?> 
 #!/bin/bash ps -ef | grep -v grep | grep capture_12hz_sampling_track.php if [ $? -eq 1 ]; then nohup /usr/local/bin/php /opt/Apache/htdocs/cmsmusic_v2/script/Mp3DownloadProcessMp4/capture_12hz_sampling_track.php & else echo "Already running" fi 

Другая альтернатива:

 <?php /** * Lock manager to ensure our cron doesn't run twice at the same time. * * Inspired by the lock mechanism in Mage_Index_Model_Process * * Usage: * * $lock = Mage::getModel('stcore/cron_lock'); * * if (!$lock->isLocked()) { * $lock->lock(); * // Do your stuff * $lock->unlock(); * } */ class ST_Core_Model_Cron_Lock extends Varien_Object { /** * Process lock properties */ protected $_isLocked = null; protected $_lockFile = null; /** * Get lock file resource * * @return resource */ protected function _getLockFile() { if ($this->_lockFile === null) { $varDir = Mage::getConfig()->getVarDir('locks'); $file = $varDir . DS . 'stcore_cron.lock'; if (is_file($file)) { $this->_lockFile = fopen($file, 'w'); } else { $this->_lockFile = fopen($file, 'x'); } fwrite($this->_lockFile, date('r')); } return $this->_lockFile; } /** * Lock process without blocking. * This method allow protect multiple process runing and fast lock validation. * * @return Mage_Index_Model_Process */ public function lock() { $this->_isLocked = true; flock($this->_getLockFile(), LOCK_EX | LOCK_NB); return $this; } /** * Lock and block process. * If new instance of the process will try validate locking state * script will wait until process will be unlocked * * @return Mage_Index_Model_Process */ public function lockAndBlock() { $this->_isLocked = true; flock($this->_getLockFile(), LOCK_EX); return $this; } /** * Unlock process * * @return Mage_Index_Model_Process */ public function unlock() { $this->_isLocked = false; flock($this->_getLockFile(), LOCK_UN); return $this; } /** * Check if process is locked * * @return bool */ public function isLocked() { if ($this->_isLocked !== null) { return $this->_isLocked; } else { $fp = $this->_getLockFile(); if (flock($fp, LOCK_EX | LOCK_NB)) { flock($fp, LOCK_UN); return false; } return true; } } /** * Close file resource if it was opened */ public function __destruct() { if ($this->_lockFile) { fclose($this->_lockFile); } } } 

Источник: https://gist.github.com/wcurtis/9539178

Я запускал скрипт задания php cron, который специально предназначался для отправки текстовых сообщений с использованием существующего API. В моем локальном поле работа cron работала нормально, но в ящике моего клиента он отправлял двойные сообщения. Хотя для меня это не имеет смысла, я дважды проверял разрешения для папки, ответственной за отправку сообщений, и для разрешения было установлено значение root. Как только я установил владельца как www-data (Ubuntu), он начал вести себя нормально.

Это может быть проблемой для вас, но если это простой скрипт cron, я бы дважды проверял разрешения.