Skip to content

Instantly share code, notes, and snippets.

@Ellrion
Last active April 4, 2018 07:30
Show Gist options
  • Save Ellrion/c01867e98fa94a65db5d8e10c0018e83 to your computer and use it in GitHub Desktop.
Save Ellrion/c01867e98fa94a65db5d8e10c0018e83 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/' . snake_case($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;
}
}
@andrey-helldar
Copy link

andrey-helldar commented Dec 15, 2017

return storage_path() . '/lock/' . strtolower(str_replace(':', '_', $this->name)) . '.lock';

Имхо, будет красивее заменив строчку на:
return storage_path('lock/' . snake_case($this->name) . '.lock');

@Ellrion
Copy link
Author

Ellrion commented Mar 19, 2018

@andrey-helldar , не принципиально, но согласен, поменял

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment