Как предотвратить выполнение задания cron, если оно уже запущено
У меня есть один php script, и я выполняю этот script через cron каждые 10 минут на CentOS.
Проблема заключается в том, что если задание cron займет более 10 минут, тогда начнется другой экземпляр того же задания cron.
Я попробовал один трюк, то есть:
- Создал один файл блокировки с кодом php (такие же, как файлы pid), когда
начало работы cron.
- Удаленный файл блокировки с php-кодом при завершении задания.
- И когда любое новое задание cron запустило выполнение script, я проверил, заблокирован ли
файл существует, и если это так, прервите script.
Но может быть одна проблема: когда файл блокировки не удаляется или не удаляется с помощью script по какой-либо причине.
Cron никогда не начнет снова.
Можно ли каким-либо образом остановить выполнение задания cron, если он уже запущен, с командами Linux или подобными этому?
Ответы
Ответ 1
Конкретная блокировка выполняется именно для этой цели.
Вы можете выполнить консультативную блокировку с помощью flock()
. Просто примените функцию к ранее открытому файлу блокировки, чтобы определить, есть ли у него script.
$f = fopen('lock', 'w') or die ('Cannot create lock file');
if (flock($f, LOCK_EX | LOCK_NB)) {
// yay
}
В этом случае я добавляю LOCK_NB
, чтобы не допустить следующего ожидания script до завершения первого. Поскольку вы используете cron, всегда будет следующий script.
Если текущий script преждевременно завершается, любые блокировки файлов будут освобождены ОС.
Ответ 2
Может быть, лучше не писать код, если вы можете его настроить:
https://serverfault.com/questions/82857/prevent-duplicate-cron-jobs-running
Ответ 3
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))
Ответ 4
Это очень распространенная проблема с очень простым решением: cronjoblock
простая 8-строчная оболочечная оболочка применяет блокировку с помощью flock:
https://gist.github.com/coderofsalvation/1102e56d3d4dcbb1e36f
кстати. cronjoblock
также отменяет cron spammy emailbehaviour: выводите только что-то, если что-то не так. Это удобно для переменной cron MAILTO. Выход stdout/stderr будет подавлен (поэтому cron не будет отправлять почту), если у данного процесса нет кода exit > 0
Ответ 5
flock не будет работать в php 5.3.3, так как автоматическая разблокировка при закрытии дескриптора файлового ресурса была удалена. Разблокирование теперь всегда должно выполняться вручную.
Ответ 6
Я использую this::
<?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");
?>
Ответ 7
#!/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
Ответ 8
Другая альтернатива:
<?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
Ответ 9
Я выполнял задание php cron script, которое специально предназначалось для отправки текстовых сообщений с использованием существующего API. В моем локальном поле работа cron работала нормально, но на моем клиентском ящике она отправляла двойные сообщения. Хотя для меня это не имеет смысла, я дважды проверял разрешения для папки, ответственной за отправку сообщений, и для разрешения было установлено значение root. Как только я установил владельца как www-data (Ubuntu), он начал вести себя нормально.
Это может быть проблемой для вас, но если это простой cron script, я бы дважды проверял разрешения.