Skip to content

Instantly share code, notes, and snippets.

@s00d
Forked from Ellrion/OverlappingControlled.php
Created September 14, 2016 23:31
Show Gist options
  • Save s00d/554a0ce5a485f714f4341d510e2eced1 to your computer and use it in GitHub Desktop.
Save s00d/554a0ce5a485f714f4341d510e2eced1 to your computer and use it in GitHub Desktop.
<?php
namespace App\Console;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
trait OverlappingControlled
{
/**
* Дескриптор файла блокировки.
*
* @var resource
*/
protected $lockHandle;
/**
* Возвращает путь к файлу блокировки.
* По-умолчанию, это "storage/lock/(имя команды).lock".
*
* @return string
*/
protected function getLockPath()
{
return storage_path() . '/lock/' . strtolower(str_replace(':', '_', $this->name)) . '.lock';
}
/**
* Возвращает флаги для захвата блокировки.
*
* @return int
*/
protected function getLockFlags()
{
return empty($this->withoutOverlapping) ? LOCK_UN : LOCK_EX | LOCK_NB;
}
/**
* Захват блокировки.
*
* @return bool
*/
protected function lock()
{
if (is_resource($this->lockHandle)) {
$this->free();
}
$this->lockHandle = fopen($this->getLockPath(), 'c');
$lock = false !== $this->lockHandle && flock($this->lockHandle, $this->getLockFlags());
if (false === $lock) {
$this->lockHandle = null;
}
return $lock;
}
/**
* Освобождение блокировки.
*
* @return bool
*/
protected function free()
{
if (!is_resource($this->lockHandle)) {
return false;
}
fflush($this->lockHandle);
flock($this->lockHandle, LOCK_UN);
fclose($this->lockHandle);
return $this->removeLockFile();
}
/**
* Удаление файла блокировки
*
* @return bool
*/
protected function removeLockFile()
{
try {
$file = $this->getLockPath();
if (is_file($file) && !is_link($file)) {
if (@unlink($file) === false) {
throw new \Exception(sprintf('Failed to remove lock file "%s".', $file));
}
} else {
return false;
}
return true;
} catch (\Exception $e) {
return false;
}
}
/**
* Проверяет, используется ли блокировка в управлении запуском.
*
* @return bool
*/
protected function isUsedLock()
{
return !empty($this->withoutOverlapping) && !$this->option('force');
}
/**
* Execute the console command.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return mixed
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
if (!$this->isUsedLock() || $this->lock()) {
$result = parent::execute($input, $output);
}
$this->free();
return $result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment