web-dev-qa-db-ja.com

すでに実行されている場合、cronジョブの実行を防ぐ方法

Phpスクリプトが1つあり、CentOSで10分ごとにcronを介してこのスクリプトを実行しています。

問題は、cronジョブに10分以上かかる場合、同じcronジョブの別のインスタンスが開始されることです。

私は1つのトリックを試しました:それは:

  1. Cronジョブの開始時に、phpコード(pidファイルと同じ)で1つのロックファイルを作成しました。
  2. ジョブが終了したときに、PHPコードを含むロックファイルを削除しました。
  3. 新しいcronジョブがスクリプトの実行を開始したときに、ロックファイルが存在するかどうかを確認し、存在する場合はスクリプトを中止しました。

しかし、ロックファイルが何らかの理由でスクリプトによって削除または削除されない場合、1つの問題が発生する可能性があります。 cronは二度と起動しません。

Linuxコマンドまたはこれに類似した、すでに実行されているcronジョブの実行を再度停止する方法はありますか?

25
Sanjay

まさにこの目的のために、アドバイザリロックが行われます。

flock() を使用すると、アドバイザリロックを実行できます。以前に開いたロックファイルに関数を適用するだけで、別のスクリプトにロックがかかっているかどうかを判断できます。

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

この場合、LOCK_NBを追加して、次のスクリプトが最初のスクリプトが終了するまで待機しないようにします。 cronを使用しているため、常に次のスクリプトがあります。

現在のスクリプトが途中で終了すると、ファイルロックがOSによって解放されます。

45
Ja͢ck

構成できる場合は、コードを記述しない方が良いかもしれません。

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

15

flock()はうまく機能しました-データベースリクエストが5分ごとにスケジュールされているcronジョブがあるので、同時にいくつかを実行しないことが重要です。これは私がやったことです:

$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ジョブを強制終了したくない場合は、実行中のcronジョブが終了するまで一時停止し、LOCK_NB

if (flock($filehandle, LOCK_EX)) 
12
mgapatrick

これは、非常に単純なソリューションでの非常に一般的な問題です。cronjoblock単純な8行のシェルスクリプトラッパーは、flockを使用してロックを適用します。

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

ところで。 cronjoblockは、cronのスパム電子メールの振る舞いも逆にします。何かがうまくいかない場合にのみ何かを出力します。これは、cronのMAILTO変数に関して便利です。 stdout/stderrの出力は抑制されます(したがって、cronはメールを送信しません)unless指定されたプロセスにexitcode> 0があります

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

既存のAPIを使用してテキストメッセージを送信することを特に扱ったphp cronジョブスクリプトを実行していました。ローカルボックスでは、cronジョブは正常に機能していましたが、顧客のボックスでは二重のメッセージを送信していました。これは私には意味がありませんが、メッセージの送信を担当するフォルダーのアクセス許可を再確認し、アクセス許可をルートに設定しました。所有者をwww-data(Ubuntu)として設定すると、正常に動作し始めました。

これはmotの問題かもしれませんが、単純なcronスクリプトである場合は、アクセス許可を再確認します。

0
Growling Flea

私はこれを使用します::

<?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");
?>
0
Dragos

ファイルのリソースハンドルが閉じられたときの自動ロック解除が削除されたため、flockはphp 5.3.3では機能しません。現在、ロック解除は常に手動で行う必要があります。

0
Ganesh Bora

別の選択肢:

<?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

0
joseantgv