-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added lock for when checking and updating pids
- Loading branch information
1 parent
2173a2b
commit d93f609
Showing
3 changed files
with
202 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?php | ||
/** | ||
* OriginPHP Framework | ||
* Copyright 2018 - 2021 Jamiel Sharief. | ||
* | ||
* Licensed under The MIT License | ||
* The above copyright notice and this permission notice shall be included in all copies or substantial | ||
* portions of the Software. | ||
* | ||
* @copyright Copyright (c) Jamiel Sharief | ||
* @link https://www.originphp.com | ||
* @license https://opensource.org/licenses/mit-license.php MIT License | ||
*/ | ||
declare(strict_types = 1); | ||
namespace Origin\Schedule; | ||
|
||
use Exception; | ||
use LogicException; | ||
use RuntimeException; | ||
|
||
/** | ||
* New class, this might be eventually moved into own namespace or into filesystem, not | ||
* sure yet. | ||
*/ | ||
class Lock | ||
{ | ||
const BLOCKING = LOCK_EX; | ||
const NON_BLOCKING = LOCK_EX | LOCK_NB; | ||
|
||
/** | ||
* Path to lock file | ||
* | ||
* @var string | ||
*/ | ||
private $path; | ||
|
||
/** | ||
* File pointer | ||
* | ||
* @var resource | ||
*/ | ||
private $fp = null; | ||
|
||
/** | ||
* @param string $path | ||
*/ | ||
public function __construct(string $name) | ||
{ | ||
$this->path = sys_get_temp_dir() . "/{$name}.lock"; | ||
} | ||
|
||
/** | ||
* Acquires a lock, if it cannot get a lock it will return false. | ||
* | ||
* @param boolean $block | ||
* @return boolean | ||
*/ | ||
public function acquire(bool $block = true): bool | ||
{ | ||
if ($this->fp) { | ||
throw new LogicException('Lock has already been acquired'); | ||
} | ||
|
||
touch($this->path); // Ensure file exists | ||
|
||
$this->fp = fopen($this->path, 'r+'); | ||
if (! $this->fp) { | ||
throw new RuntimeException('Error opening file'); | ||
} | ||
|
||
if (! flock($this->fp, $block ? self::BLOCKING : self::NON_BLOCKING)) { | ||
$this->closeFile(); | ||
|
||
return false; | ||
} | ||
|
||
return ftruncate($this->fp, 0) && fwrite($this->fp, (string) getmypid()) && fflush($this->fp); | ||
} | ||
|
||
/** | ||
* Releases the lock | ||
* | ||
* @return void | ||
*/ | ||
public function release(): void | ||
{ | ||
if (! $this->fp) { | ||
throw new LogicException('Lock was not acquired'); | ||
} | ||
|
||
if (! flock($this->fp, LOCK_UN)) { | ||
throw new RuntimeException('Error releasing lock'); | ||
} | ||
|
||
$this->closeFile(); | ||
} | ||
|
||
/** | ||
* Close the file if its still open | ||
*/ | ||
public function __destruct() | ||
{ | ||
$this->closeFile(); | ||
} | ||
|
||
/** | ||
* Closes the file and cleans up | ||
* | ||
* @return void | ||
*/ | ||
private function closeFile(): void | ||
{ | ||
if ($this->fp && ! fclose($this->fp)) { | ||
throw new Exception('Error closing file'); | ||
} | ||
$this->fp = null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?php | ||
/** | ||
* OriginPHP Framework | ||
* Copyright 2018 - 2021 Jamiel Sharief. | ||
* | ||
* Licensed under The MIT License | ||
* The above copyright notice and this permission notice shall be included in all copies or substantial | ||
* portions of the Software. | ||
* | ||
* @copyright Copyright (c) Jamiel Sharief | ||
* @link https://www.originphp.com | ||
* @license https://opensource.org/licenses/mit-license.php MIT License | ||
*/ | ||
namespace Origin\Test\TestCase\Schedule; | ||
|
||
use LogicException; | ||
use Origin\Schedule\Lock; | ||
|
||
class LockTest extends \PHPUnit\Framework\TestCase | ||
{ | ||
public function testAcquire() | ||
{ | ||
$lock = new Lock('test'); | ||
$file = sys_get_temp_dir() . '/test.lock'; | ||
$this->assertFileDoesNotExist($file); | ||
$this->assertTrue($lock->acquire()); | ||
$this->assertFileExists($file); | ||
$this->assertEquals((string) getmypid(), trim(file_get_contents($file))); | ||
} | ||
|
||
public function testAcquireAlreadyLocked() | ||
{ | ||
$lock = new Lock('test'); | ||
$this->assertTrue($lock->acquire()); | ||
|
||
$this->expectException(LogicException::class); | ||
$lock->acquire(); | ||
} | ||
|
||
public function testAcquireUnableToGetLock() | ||
{ | ||
$lock1 = new Lock('test'); | ||
$lock2 = new Lock('test'); | ||
|
||
$this->assertTrue($lock1->acquire()); | ||
$this->assertFalse($lock2->acquire(false)); | ||
} | ||
|
||
public function testRelease() | ||
{ | ||
$lock1 = new Lock('test'); | ||
$lock2 = new Lock('test'); | ||
|
||
$this->assertTrue($lock1->acquire()); | ||
$this->assertFalse($lock2->acquire(false)); | ||
$lock1->release(); | ||
$this->assertTrue($lock2->acquire(false)); | ||
} | ||
|
||
public function testReleaseNotAcquired() | ||
{ | ||
$lock = new Lock('test'); | ||
$this->expectException(LogicException::class); | ||
$lock->release(); | ||
} | ||
|
||
protected function setUp(): void | ||
{ | ||
$file = sys_get_temp_dir() . '/test.lock'; | ||
if (file_exists($file)) { | ||
unlink($file); | ||
} | ||
} | ||
} |