Created
September 14, 2016 12:36
Revisions
-
Ellrion created this gist
Sep 14, 2016 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,165 @@ <?php namespace App\Console; use Illuminate\Console\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class BaseCommand extends Command { /** * Обычный запуск команды. * Возможно конкурентное выполнение команды. */ const RUN_SIMPLE = 0; /** * Эксклюзивный запуск команды. * Выполняется только один экземпляр команды. */ const RUN_BLOCKING = 1; /** * Организует очередь экземпляров команд. * Выполняется только один экземпляр команды, * каждый последующий запуск команды помещает ее в очередь на выполнение. */ const RUN_QUEUE = 2; /** * Управление запуском команды. Задается константой с префиксом "RUN_". * * @var int */ protected $behavior = self::RUN_SIMPLE; /** * Дескриптор файла блокировки. * * @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() { switch ($this->behavior) { case self::RUN_BLOCKING: return LOCK_EX | LOCK_NB; case self::RUN_QUEUE: return LOCK_EX; default: return LOCK_UN; } } /** * Захват блокировки. * * @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 $this->behavior !== self::RUN_SIMPLE; } /** * 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()) { $method = method_exists($this, 'handle') ? 'handle' : 'fire'; call_user_func([$this, $method]); } $this->free(); } }