Add Storage::getLock() for exclusive access to a named lock

여러 프로세스를 동시에 실행할 경우 1개만 작동하도록
lock을 관리하는 기능을 코어 프레임워크에서 제공하도록 한다.

두 개 이상의 프로세스에서 동일한 이름의 lock을 요청할 경우
먼저 요청한 프로세스는 true, 나머지 프로세스들은 false를 받게 된다.
lock을 갖고 있던 프로세스가 종료되면 다시 요청할 수 있다.

예를 들어 크론탭에서 1분마다 실행하는 CLI 스크립트가 있는데
간혹 1분 이상 소요된다면 2개가 동시에 실행될 수도 있다.
이 때 lock을 받지 못한 쪽을 종료하면 동시 실행을 방지할 수 있다.
This commit is contained in:
Kijin Sung 2018-05-30 21:04:30 +09:00
parent f278ae5e75
commit 4533dacd4b

View file

@ -22,6 +22,11 @@ class Storage
*/
protected static $_opcache;
/**
* Cache locks here.
*/
protected static $_locks = array();
/**
* Check if a path really exists.
*
@ -858,4 +863,58 @@ class Storage
}
}
}
/**
* Obtain an exclusive lock.
*
* @return bool
*/
public static function getLock($name)
{
$name = str_replace('.', '%2E', rawurlencode($name));
if (isset(self::$_locks[$name]))
{
return false;
}
$lockdir = \RX_BASEDIR . 'files/locks';
if (!self::isDirectory($lockdir) && !self::createDirectory($lockdir))
{
return false;
}
self::$_locks[$name] = @fopen($lockdir . '/' . $name . '.lock', 'w');
if (!self::$_locks[$name])
{
unset(self::$_locks[$name]);
return false;
}
$result = @flock(self::$_locks[$name], \LOCK_EX | \LOCK_NB);
if (!$result)
{
@fclose(self::$_locks[$name]);
unset(self::$_locks[$name]);
return false;
}
register_shutdown_function('\\Rhymix\\Framework\\Storage::clearLocks');
return true;
}
/**
* Clear all locks.
*
* @return void
*/
public static function clearLocks()
{
foreach (self::$_locks as $name => $lock)
{
@flock($lock, \LOCK_UN);
@fclose($lock);
@unlink(\RX_BASEDIR . 'files/locks/' . $name . '.lock');
unset(self::$_locks[$name]);
}
}
}