php flock 超时,php flock失效问题
這兩天給自己的業(yè)余項(xiàng)目寫了一個(gè)方法,用來避免crontab調(diào)度的PHP腳本并發(fā)執(zhí)行。
做法
一般通過使用文件鎖flock方法,令相同的PHP腳本采用非阻塞鎖同一個(gè)磁盤文件,如果文件被占用則會(huì)報(bào)錯(cuò),從而可以腳本立即退出。
現(xiàn)象
但實(shí)踐中發(fā)現(xiàn),在controller文件中直接flock是可以實(shí)現(xiàn)的,當(dāng)把flock的邏輯封裝到其他文件的一個(gè)函數(shù)中后就失效了。
原因
調(diào)試了半天,突然想起來以前就遇到過這個(gè)神坑。。
錯(cuò)誤代碼如下:
PHP
class Crontab
{
/**
* 確保任務(wù)沒有并發(fā)執(zhí)行
*/
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
classCrontab
{
/**
* 確保任務(wù)沒有并發(fā)執(zhí)行
*/
publicstaticfunctionisRunning(){
global$argv;
$ident=[];
foreach($argvas$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;
}
}
根據(jù)命令行參數(shù)生成唯一hash值,代表該P(yáng)HP任務(wù)。
創(chuàng)建鎖文件,執(zhí)行flock非阻塞鎖,返回wouldBlock標(biāo)識(shí)鎖是否已被占用。
我在腳本入口調(diào)用了Crontab::isRunning()方法,發(fā)現(xiàn)并發(fā)啟動(dòng)腳本后,總是能獲得鎖。
錯(cuò)誤原因是:isRunning()方法退出后,$file_lock沒有繼續(xù)使用,被PHP垃圾回收,$fp文件句柄關(guān)閉導(dǎo)致鎖自動(dòng)釋放。
解決
PHP
class Crontab
{
/**
* 保存起來避免被php作為垃圾回收
* @var null
*/
static $file_lock = null;
/**
* 確保任務(wù)沒有并發(fā)執(zhí)行
*/
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
classCrontab
{
/**
* 保存起來避免被php作為垃圾回收
* @var null
*/
static$file_lock=null;
/**
* 確保任務(wù)沒有并發(fā)執(zhí)行
*/
publicstaticfunctionisRunning(){
global$argv;
$ident=[];
foreach($argvas$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;
}
}
確保在整個(gè)PHP生命期內(nèi),文件句柄都不會(huì)被釋放即可,所以保存在類靜態(tài)成員變量里。
如果文章幫助您解決了工作難題,您可以幫我點(diǎn)擊屏幕上的任意廣告,或者贊助少量費(fèi)用來支持我的持續(xù)創(chuàng)作,謝謝~
總結(jié)
以上是生活随笔為你收集整理的php flock 超时,php flock失效问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 如何添加数据文件,Orac
- 下一篇: oracle怎么关闭约束,Oracle约