概述
【应用背景】
平时一些脚本,比如上篇文章【crontab通过shell脚本执行业务脚本】用到php的脚本,像【r_gap_basic_day.php】是用来实时统计当天游戏-渠道-广告位维度的注册活跃付费等基础数据的,crontab是设定的8分钟执行一次,那如果脚本有问题,导致上一次脚本执行没完,后面脚本又开始执行了,那就可能导致数据错乱问题。或者另外一种情况,想看当前数据,手动执行的时候恰好碰到定时任务也在执行,就可能出现冲突。这时候就需要一个机制,当脚本已经在执行了,就提示不再重复。本文要介绍的文件进程锁,就是这个机制的一种实现方式,主要逻辑就是:
1、php脚本执行的时候,调用进程锁类,把当前执行的进程id记录下来文件(也可以考虑记录到其它地方),当脚本执行完毕时候删除进程标识(这个很有必要,有些情况可能进程id结束后被系统复用,比如被一个常用进程用上了就一直存在锁着了)。
2、php脚本执行前增加一个监测,是否该文件的进程id还存在着,如果有就表示上一次执行还在,不能继续执行,否则继续
3、也可以优化下,针对一些假死进程(或者脚本bug没走到删除进程文件地方),比如进程锁太久了,一天还没释放,那大概率就是有问题的了,这时候可以直接清除。
4、最初也考虑过在脚本执行初期reids记录标识,在执行结束删除,但是当脚本中间退出就会导致没删除,以为一直锁住。后面才引入了进程id的概念,即使中间退出也可以通过进程id检验到是否在执行中
【进程锁类文件-loglock.php】
<?php
/*
检查进程是否存在,存在返回1,不存在返回0
*/
class LogLock {
private static $_instance = null;
public function getlock($name) {
$lock = $name.".lock";
if (file_exists($lock)) {
$check_pid = file_get_contents($lock);
system("kill -CHLD " . $check_pid . " 1> /dev/null 2> /dev/null", $check_pid_return);
if($check_pid_return == 1)
{
//存在已经假死的进程,或进程不存在
return 0;
}
else {
//已存在正在运行的进程
return 1;
}
} else {
//不存在锁文件
return 0;
}
}
/*
给当前进程上锁
*/
public function lockit($name)
{
$lock = $name.".lock";
file_put_contents($lock,getmypid());
}
/*
删除进程锁
*/
public function unlock($name)
{
$lock = $name.".lock";
@unlink($lock);
}
/**
* 获取单例
*
* @return Sylogbase
*/
public static function getInstance()
{
if (self::$_instance instanceof self) {
return self::$instance;
}
return new self();
}
}
【测试用例】
类似下面测试用例【testLock.php】,脚本执行过程中,就会在lock日志目录下生成对应的进程锁文件testLock.php.lock(里面记录着运行的进程id),当脚本执行结束,就会把文件删除。
<?php
date_default_timezone_set('Asia/Shanghai');
include 'loglock.php';
$obj = new TestLock($_SERVER["PHP_SELF"]);
class TestLock
{
public $logDir; //锁文件位置
public $lockName; //锁文件名称
/**
*
* @param string $lockName 对应脚本名,可作为锁文件名
* @param string $param 脚本参数信息
* @param int $timeType 脚本运行时间类型(1=实时,2=天一次,3=周一次,4=月一次)
*/
public function __construct($lockName, $param = null, $timeType = 1)
{
$this->lockName = $lockName;
$this->logDir = '/tmp/lock_log/';
//判断文件进程锁
if (!$this->checkLock()) {
$this->writeLog($this->lockName . '已经在运行了!');
}
$this->setParamAndRun();
$this->writeLog('结束运行' . $this->lockName, false);
$this->unlock();
}
//设置参数和执行脚本逻辑代码
public function setParamAndRun()
{
sleep(5);
return;
}
/**
* 判断是否可以执行该文件(是否已经在运行了)
* @return true=可以执行,false=不能执行
*/
public function checkLock(){
$lockObj = LogLock::getInstance();
$lock = $lockObj->getlock($this->logDir.$this->lockName);
if ($lock) {
return false;
}else{
$lockObj->lockit($this->logDir.$this->lockName);
return true;
}
}
/**
* 执行完脚本删除lock文件
*/
public function unlock(){
$lockObj = LogLock::getInstance();
$lock = $lockObj->unlock($this->logDir.$this->lockName);
}
/**
* 记录日志
* @return true=是,false=不是
*/
public function writeLog($msg,$isExist=true){
$nowTimeStr = date('Y-m-d H:i:s',time());
$msg = '====='.$nowTimeStr.'====='.$msg."n";
echo $msg;
if($isExist){
exit;
}
}
}
最后
以上就是火星上大树为你收集整理的脚本文件执行进程锁-防重复执行的全部内容,希望文章能够帮你解决脚本文件执行进程锁-防重复执行所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复