What should I do if the flock php lock fails?

藏色散人
Release: 2023-03-13 18:16:01
Original
2236 people have browsed it

flock PHP lock failed because $file_lock was not used after the isRunning() method exited. The solution is to ensure that the file handle will not be released during the entire PHP life cycle. .

What should I do if the flock php lock fails?

The operating environment of this article: Windows 7 system, PHP version 7.1, DELL G3 computer

What should I do if the php lock fails?

Solution to the problem of php flock failure:

In the past two days, I wrote a method for my side project to avoid concurrent execution of PHP scripts scheduled by crontab .

How to do it

Generally, by using the file lock flock method, the same PHP script uses non-blocking locking of the same disk file. If the file is occupied, an error will be reported, thus The script can exit immediately.

Phenomena

But in practice, it is found that it is possible to directly flock in the controller file. When the flock logic is encapsulated into a function in other files, failed.

Cause

After debugging for a long time, I suddenly remembered that I had encountered this pit before. .

The error code is as follows:

class Crontab
{
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
        @mkdir($lockDir, 0755, true);
        $file_lock = fopen($lockDir . $ident, 'w+');
        $wouldBlock = 0;
        flock($file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
        return $wouldBlock;
    }
}
Copy after login
class Crontab
{
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
 
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
 
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
 
        @mkdir($lockDir, 0755, true);
 
        $file_lock = fopen($lockDir . $ident, 'w+');
 
        $wouldBlock = 0;
        flock($file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
 
        return $wouldBlock;
    }
}
Copy after login

Generate a unique hash value based on the command line parameters, representing the PHP task.

Create a lock file, execute flock non-blocking lock, and return wouldBlock to identify whether the lock has been occupied.

I called the Crontab::isRunning() method at the script entry and found that after starting the script concurrently, the lock can always be obtained.

The reason for the error is: after the isRunning() method exits, $file_lock is not continued to be used and is garbage collected by PHP. The $fp file handle is closed, causing the lock to be automatically released.

Solution

class Crontab
{
    /**
     * 保存起来避免被php作为垃圾回收
     * @var null
     */
    static $file_lock = null;
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
        @mkdir($lockDir, 0755, true);
        self::$file_lock = fopen($lockDir . $ident, 'w+');
        $wouldBlock = 0;
        flock(self::$file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
        return $wouldBlock;
    }
}
Copy after login
class Crontab
{
    /**
     * 保存起来避免被php作为垃圾回收
     * @var null
     */
    static $file_lock = null;
 
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
 
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
 
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
 
        @mkdir($lockDir, 0755, true);
 
        self::$file_lock = fopen($lockDir . $ident, 'w+');
 
        $wouldBlock = 0;
        flock(self::$file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
 
        return $wouldBlock;
    }
}
Copy after login

Just make sure that the file handle will not be released during the entire PHP life cycle, so it is saved in the class static member variable.

Recommended learning: "PHP Video Tutorial"

The above is the detailed content of What should I do if the flock php lock fails?. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template