如果已经运行,如何阻止cron作业执行

时间:2021-08-04 08:01:46

I have one php script, and I am executing this script via cron every 10 minutes on CentOS.

我有一个PHP脚本,我在CentOS上每隔10分钟通过cron执行这个脚本。

The problem is that if the cron job will take more than 10 minutes, then another instance of the same cron job will start.

问题是如果cron作业需要10分钟以上,那么同一个cron作业的另一个实例将启动。

I tried one trick, that is:

我尝试了一个技巧,那就是:

  1. Created one lock file with php code (same like pid files) when the cron job started.
  2. 在cron作业启动时,使用php代码创建一个锁定文件(与pid文件相同)。
  3. Removed the lock file with php code when the job finished.
  4. 作业完成后,使用php代码删除了锁定文件。
  5. And when any new cron job started execution of script, I checked if lock file exists and if so, aborted the script.
  6. 当任何新的cron作业开始执行脚本时,我检查了锁文件是否存在,如果存在,则中止脚本。

But there can be one problem that, when the lock file is not deleted or removed by script because of any reason. The cron will never start again.

但是,当由于任何原因未通过脚本删除或删除锁定文件时,可能存在一个问题。 cron永远不会重新开始。

Is there any way I can stop the execution of a cron job again if it is already running, with Linux commands or similar to this?

有没有办法我可以再次执行cron作业,如果它已经在运行,使用Linux命令或类似的?

9 个解决方案

#1


42  

Advisory locking is made for exactly this purpose.

咨询锁定就是为了这个目的。

You can accomplish advisory locking with flock(). Simply apply the function to a previously opened lock file to determine if another script has a lock on it.

您可以使用flock()完成建议锁定。只需将该函数应用于先前打开的锁定文件,以确定其他脚本是否具有锁定。

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

In this case I'm adding LOCK_NB to prevent the next script from waiting until the first has finished. Since you're using cron there will always be a next script.

在这种情况下,我正在添加LOCK_NB以防止下一个脚本等到第一个脚本完成。由于您使用的是cron,因此总会有下一个脚本。

If the current script prematurely terminates, any file locks will get released by the OS.

如果当前脚本过早终止,则操作系统将释放任何文件锁。

#2


15  

Maybe it is better to not write code if you can configure it:

也许最好不要编写代码,如果你可以配置它:

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

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

#3


12  

flock() worked out great for me - I have a cron job with database requests scheduled every 5 minutes, so not having several running at the same time is crucial. This is what I did:

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);

In case you don't want to kill the next scheduled cron job, but simply pause it till the running one is finished, then just omit the LOCK_NB:

如果你不想杀死下一个预定的cron作业,只是暂停它直到正在运行的作业完成,那么只需省略LOCK_NB:

if (flock($filehandle, LOCK_EX)) 

#4


1  

This is a very common problem with a very simple solution: cronjoblock a simple 8-lines shellscript wrapper applies locking using flock:

这是一个非常简单的解决方案的常见问题:cronjoblock一个简单的8行shellcript包装器使用flock应用锁定:

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

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

btw. cronjoblock also reverses cron's spammy emailbehaviour: only output something if stuff goes wrong. This is handy in respect to cron's MAILTO variable. The stdout/stderr output will be suppressed (so cron will not send mails) unless the given process has an exitcode > 0

顺便说一句。 cronjoblock还反转了cron的垃圾邮件电子邮件:只有在出现问题时才输出内容。这对于cron的MAILTO变量很方便。 stdout / stderr输出将被抑制(因此cron不会发送邮件),除非给定进程的exitcode> 0

#5


0  

flock will not work in php 5.3.3 as The automatic unlocking when the file's resource handle is closed was removed. Unlocking now always has to be done manually.

flock将无法在php 5.3.3中工作,因为删除了文件资源句柄关闭时的自动解锁。现在解锁总是必须手动完成。

#6


0  

I use 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


0  

#!/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


0  

Another alternative:

另一种选择:

<?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);
        }
    }
}

Source: https://gist.github.com/wcurtis/9539178

资料来源:https://gist.github.com/wcurtis/9539178

#9


0  

I was running a php cron job script that dealt specifically with sending text messages using an existing API. On my local box the cron job was working fine, but on my customer's box it was sending double messages. Although this doesn't make sense to me, I double checked the permissions for the folder responsible for sending messages and the permission was set to root. Once I set the owner as www-data (Ubuntu) it started behaving normally.

我正在运行一个php cron作业脚本,专门用于使用现有API发送文本消息。在我的本地方框上,cron工作正常,但在我的客户盒子上发送了双重消息。虽然这对我没有意义,但我仔细检查了负责发送邮件的文件夹的权限,并将权限设置为root。一旦我将所有者设置为www-data(Ubuntu),它就开始正常运行。

This might mot be the issue for you, but if its a simple cron script I would double check the permissions.

这可能是你的问题,但如果它是一个简单的cron脚本,我会仔细检查权限。

#1


42  

Advisory locking is made for exactly this purpose.

咨询锁定就是为了这个目的。

You can accomplish advisory locking with flock(). Simply apply the function to a previously opened lock file to determine if another script has a lock on it.

您可以使用flock()完成建议锁定。只需将该函数应用于先前打开的锁定文件,以确定其他脚本是否具有锁定。

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

In this case I'm adding LOCK_NB to prevent the next script from waiting until the first has finished. Since you're using cron there will always be a next script.

在这种情况下,我正在添加LOCK_NB以防止下一个脚本等到第一个脚本完成。由于您使用的是cron,因此总会有下一个脚本。

If the current script prematurely terminates, any file locks will get released by the OS.

如果当前脚本过早终止,则操作系统将释放任何文件锁。

#2


15  

Maybe it is better to not write code if you can configure it:

也许最好不要编写代码,如果你可以配置它:

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

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

#3


12  

flock() worked out great for me - I have a cron job with database requests scheduled every 5 minutes, so not having several running at the same time is crucial. This is what I did:

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);

In case you don't want to kill the next scheduled cron job, but simply pause it till the running one is finished, then just omit the LOCK_NB:

如果你不想杀死下一个预定的cron作业,只是暂停它直到正在运行的作业完成,那么只需省略LOCK_NB:

if (flock($filehandle, LOCK_EX)) 

#4


1  

This is a very common problem with a very simple solution: cronjoblock a simple 8-lines shellscript wrapper applies locking using flock:

这是一个非常简单的解决方案的常见问题:cronjoblock一个简单的8行shellcript包装器使用flock应用锁定:

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

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

btw. cronjoblock also reverses cron's spammy emailbehaviour: only output something if stuff goes wrong. This is handy in respect to cron's MAILTO variable. The stdout/stderr output will be suppressed (so cron will not send mails) unless the given process has an exitcode > 0

顺便说一句。 cronjoblock还反转了cron的垃圾邮件电子邮件:只有在出现问题时才输出内容。这对于cron的MAILTO变量很方便。 stdout / stderr输出将被抑制(因此cron不会发送邮件),除非给定进程的exitcode> 0

#5


0  

flock will not work in php 5.3.3 as The automatic unlocking when the file's resource handle is closed was removed. Unlocking now always has to be done manually.

flock将无法在php 5.3.3中工作,因为删除了文件资源句柄关闭时的自动解锁。现在解锁总是必须手动完成。

#6


0  

I use 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


0  

#!/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


0  

Another alternative:

另一种选择:

<?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);
        }
    }
}

Source: https://gist.github.com/wcurtis/9539178

资料来源:https://gist.github.com/wcurtis/9539178

#9


0  

I was running a php cron job script that dealt specifically with sending text messages using an existing API. On my local box the cron job was working fine, but on my customer's box it was sending double messages. Although this doesn't make sense to me, I double checked the permissions for the folder responsible for sending messages and the permission was set to root. Once I set the owner as www-data (Ubuntu) it started behaving normally.

我正在运行一个php cron作业脚本,专门用于使用现有API发送文本消息。在我的本地方框上,cron工作正常,但在我的客户盒子上发送了双重消息。虽然这对我没有意义,但我仔细检查了负责发送邮件的文件夹的权限,并将权限设置为root。一旦我将所有者设置为www-data(Ubuntu),它就开始正常运行。

This might mot be the issue for you, but if its a simple cron script I would double check the permissions.

这可能是你的问题,但如果它是一个简单的cron脚本,我会仔细检查权限。