alex-kalanis /
kw_clipr
| 1 | <?php |
||
| 2 | |||
| 3 | namespace kalanis\kw_clipr\Tasks; |
||
| 4 | |||
| 5 | |||
| 6 | use kalanis\kw_clipr\CliprException; |
||
| 7 | use kalanis\kw_locks\Interfaces\ILock; |
||
| 8 | use kalanis\kw_locks\Interfaces\IPassedKey; |
||
| 9 | use kalanis\kw_locks\LockException; |
||
| 10 | use kalanis\kw_locks\Methods\PidLock; |
||
| 11 | |||
| 12 | |||
| 13 | /** |
||
| 14 | * Class ASingleTask |
||
| 15 | * @package kalanis\kw_clipr\Tasks |
||
| 16 | * @property bool $singleInstance |
||
| 17 | */ |
||
| 18 | abstract class ASingleTask extends ATask |
||
| 19 | { |
||
| 20 | protected ILock $lock; |
||
| 21 | |||
| 22 | /** |
||
| 23 | * @param ILock|null $lock |
||
| 24 | * @throws LockException |
||
| 25 | */ |
||
| 26 | 7 | public function __construct(?ILock $lock = null) |
|
| 27 | { |
||
| 28 | 7 | $this->lock = $lock ?: $this->getPresetLock(); |
|
| 29 | 7 | if ($this->lock instanceof IPassedKey) { |
|
| 30 | 2 | $this->lock->setKey(str_replace('/', ':', get_class($this)) . ILock::LOCK_FILE); |
|
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 31 | 5 | } elseif (method_exists($this->lock, 'setClass')) { |
|
| 32 | 1 | $this->lock->/** @scrutinizer ignore-call */setClass($this); |
|
| 33 | } |
||
| 34 | // lock target must go via lock's constructor |
||
| 35 | // when it comes via IStorage (StorageLock), it's possible to connect it into Redis or Memcache and then that path might not be necessary |
||
| 36 | 7 | } |
|
| 37 | |||
| 38 | /** |
||
| 39 | * @throws LockException |
||
| 40 | * @return ILock |
||
| 41 | */ |
||
| 42 | 1 | protected function getPresetLock(): ILock |
|
| 43 | { |
||
| 44 | 1 | return new PidLock($this->getTempPath()); |
|
| 45 | } |
||
| 46 | |||
| 47 | 1 | protected function getTempPath(): string |
|
| 48 | { |
||
| 49 | 1 | return '/tmp'; |
|
| 50 | } |
||
| 51 | |||
| 52 | /** |
||
| 53 | * @throws CliprException |
||
| 54 | */ |
||
| 55 | 4 | protected function startup(): void |
|
| 56 | { |
||
| 57 | 4 | parent::startup(); |
|
| 58 | 4 | $this->params->addParam('singleInstance', 'single-instance', null, false, 's', 'Call only single instance'); |
|
| 59 | |||
| 60 | 4 | $this->checkSingleInstance(); |
|
| 61 | 3 | } |
|
| 62 | |||
| 63 | /** |
||
| 64 | * @throws CliprException |
||
| 65 | */ |
||
| 66 | 4 | protected function checkSingleInstance(): void |
|
| 67 | { |
||
| 68 | try { |
||
| 69 | 4 | if ($this->isSingleInstance() && $this->isRunLocked()) { |
|
| 70 | // check if exists another instance |
||
| 71 | 3 | throw new SingleTaskException('One script instance is already running!', static::STATUS_ATTEMPT_LATER); |
|
| 72 | // create own lock file |
||
| 73 | } |
||
| 74 | 2 | } catch (LockException $ex) { |
|
| 75 | 1 | throw new SingleTaskException('Locked by another user. Cannot unlock here.', static::STATUS_PERMISSION_BLOCK, $ex); |
|
| 76 | } |
||
| 77 | 3 | } |
|
| 78 | |||
| 79 | 4 | protected function isSingleInstance(): bool |
|
| 80 | { |
||
| 81 | 4 | return (true === $this->singleInstance); |
|
| 82 | } |
||
| 83 | |||
| 84 | /** |
||
| 85 | * @throws LockException |
||
| 86 | * @return bool |
||
| 87 | */ |
||
| 88 | 4 | protected function isRunLocked(): bool |
|
| 89 | { |
||
| 90 | try { |
||
| 91 | 4 | if (!$this->lock->has()) { |
|
| 92 | 4 | $this->lock->create(); |
|
| 93 | 2 | return false; |
|
| 94 | } |
||
| 95 | 1 | return true; |
|
| 96 | 2 | } catch (LockException $ex) { |
|
| 97 | 2 | $this->writeLn('Removing stale lock file.'); |
|
| 98 | 2 | $this->lock->delete(true); |
|
| 99 | 1 | return false; |
|
| 100 | } |
||
| 101 | } |
||
| 102 | } |
||
| 103 |