Skip to content

Instantly share code, notes, and snippets.

@phackwer
Last active August 2, 2017 12:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phackwer/1423f7049eceda55f315e6d264d10721 to your computer and use it in GitHub Desktop.
Save phackwer/1423f7049eceda55f315e6d264d10721 to your computer and use it in GitHub Desktop.
Laravel Singleton
<?php
namespace App\Console;
use Illuminate\Console\Command;
/**
* Class PidLockingCommand
*
* Implements a command with pidlocking control to avoid conflicting processing
* Extend this class and call parent::handle() on top of your handle().
*
* @package App\Console\Commands
*/
abstract class AbstractSingletonCommand extends Command
{
/**
* @var Lock file with PID value, used to avoid running the importer while still extracting data
*/
protected $pidFile;
public function __destruct()
{
$this->removePidLock();
}
public function getPid()
{
if (file_exists($this->pidFile)) {
$pid = file_get_contents($this->pidFile);
return $this->checkIfProcessIsReallyRunning($pid);
} else {
return null;
}
}
public function checkIfProcessIsReallyRunning($pid)
{
$pids = '';
$fp = popen("ps ax -o pid --noheaders", "r");
while (!feof($fp)) {
$pids .= fread($fp, 1024);
}
fclose($fp);
$pids = explode("\n", $pids);
if (!in_array($pid, $pids)) {
unlink($this->pidFile);
return null;
}
return $pid;
}
protected function setPid()
{
file_put_contents($this->pidFile, getmypid());
}
protected function removePidLock()
{
if (file_exists($this->pidFile) && $this->checkMyPid()) {
unlink($this->pidFile);
}
}
protected function checkMyPid()
{
return $this->getPid() == getmypid();
}
protected function generateFileName()
{
return base_path() . DIRECTORY_SEPARATOR .
"storage" .
DIRECTORY_SEPARATOR .
snake_case($this->getSingleClassName());
}
protected function setPidFile()
{
$this->pidFile = $this->generateFileName() . '.pid';
}
public function getSingleClassName($class = null)
{
$class = is_string($class) ? $class : get_class($this);
$class = explode('\\', $class);
return $class[count($class) - 1];
}
public function __construct()
{
parent::__construct();
$this->setPidFile();
}
public function handle()
{
// if no process is running
if (!$this->getPid()) {
$this->setPid();
}
if ($this->getPid() && !$this->checkMyPid()) {
trigger_error('Previous ' . $this->getSingleClassName() . ' process still running!!!', E_USER_ERROR);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment