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. .
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; } }
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; } }
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; } }
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; } }
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!