22
33namespace Aternos \Lock ;
44
5- use Aternos \Etcd \Client ;
6- use Aternos \Etcd \ClientInterface ;
7- use Aternos \Etcd \Exception \Status \DeadlineExceededException ;
8- use Aternos \Etcd \Exception \Status \InvalidResponseStatusCodeException ;
9- use Aternos \Etcd \Exception \Status \UnavailableException ;
10- use Aternos \Etcd \Exception \Status \UnknownException ;
5+ use Aternos \Lock \Storage \EtcdStorage ;
6+ use Aternos \Lock \Storage \StorageException ;
7+ use Aternos \Lock \Storage \StorageInterface ;
8+ use Exception ;
119
1210/**
13- * Class Lock
11+ * LockInterface implementation using etcd-like storage
1412 *
1513 * @package Aternos\Lock
1614 */
1715class Lock extends AbstractLock
1816{
1917 /**
20- * see Lock::setClient()
21- *
22- * @var ClientInterface|null
18+ * @see static::setStorage()
19+ * @var StorageInterface|null
2320 */
24- protected static ?ClientInterface $ client = null ;
21+ protected static ?StorageInterface $ storage = null ;
2522
2623 /**
2724 * see Lock::setPrefix()
@@ -66,15 +63,22 @@ class Lock extends AbstractLock
6663 protected static int $ delayPerUnavailableRetry = 1 ;
6764
6865 /**
69- * Set the etcd client (Aternos\Etcd\Client)
70- *
71- * Uses a localhost client if not set
72- *
73- * @param ClientInterface $client
66+ * Set the storage interface used to store locks. If not set, {@link EtcdStorage} is used.
67+ * @param StorageInterface $storage
68+ * @return void
69+ */
70+ public static function setStorage (StorageInterface $ storage ): void
71+ {
72+ static ::$ storage = $ storage ;
73+ }
74+
75+ /**
76+ * Get the storage interface used to store locks. If not set, {@link EtcdStorage} is used.
77+ * @return StorageInterface
7478 */
75- public static function setClient ( ClientInterface $ client ): void
79+ protected static function getStorage ( ): StorageInterface
7680 {
77- static ::$ client = $ client ;
81+ return static ::$ storage ??= new EtcdStorage () ;
7882 }
7983
8084 /**
@@ -110,12 +114,13 @@ public static function setMaxSaveRetries(int $retries): void
110114 }
111115
112116 /**
113- * Set the maximum delay in microseconds (1,000,000 microseconds = 1 second) that should used for the random delay between retries
117+ * Set the maximum delay in microseconds (1,000,000 microseconds = 1 second) that should be used for the random
118+ * delay between retries.
114119 *
115120 * The delay is random and calculated like this: rand(0, $retries * $delayPerRetry)
116121 *
117122 * Lower value = faster retries (probably more retries necessary)
118- * Higher value = slower retries (probably less retries necessary)
123+ * Higher value = slower retries (probably fewer retries necessary)
119124 *
120125 * @param int $delayPerRetry
121126 */
@@ -144,20 +149,6 @@ public static function setDelayPerUnavailableRetry(int $delayPerRetry): void
144149 static ::$ delayPerUnavailableRetry = $ delayPerRetry ;
145150 }
146151
147- /**
148- * Get an Aternos\Etcd\Client instance
149- *
150- * @return ClientInterface
151- */
152- protected static function getClient (): ClientInterface
153- {
154- if (static ::$ client === null ) {
155- static ::$ client = new Client ();
156- }
157-
158- return static ::$ client ;
159- }
160-
161152 /**
162153 * Full name of the key in etcd (prefix + key)
163154 *
@@ -222,7 +213,7 @@ public function __construct(
222213 * Try to acquire lock
223214 *
224215 * @return bool true if the lock was acquired, false if it was not
225- * @throws InvalidResponseStatusCodeException
216+ * @throws StorageException
226217 * @throws TooManySaveRetriesException
227218 */
228219 public function lock (): bool
@@ -247,7 +238,7 @@ public function lock(): bool
247238 *
248239 * @param int|null $waitTime maximum time in seconds to wait for other locks
249240 * @return bool
250- * @throws InvalidResponseStatusCodeException
241+ * @throws StorageException
251242 */
252243 public function waitForOtherLocks (?int $ waitTime = null ): bool
253244 {
@@ -284,7 +275,7 @@ public function getRemainingLockDuration(): int
284275 * Refresh the lock
285276 *
286277 * @return boolean
287- * @throws InvalidResponseStatusCodeException
278+ * @throws StorageException
288279 * @throws TooManySaveRetriesException
289280 */
290281 public function refresh (): bool
@@ -312,7 +303,7 @@ public function refresh(): bool
312303 * Should be only used if you have the lock
313304 *
314305 * @return void
315- * @throws InvalidResponseStatusCodeException
306+ * @throws StorageException
316307 * @throws TooManySaveRetriesException
317308 */
318309 public function break (): void
@@ -340,7 +331,7 @@ protected function generateLock(): LockEntry
340331 * Remove a lock from the locking array and save the locks
341332 *
342333 * @return void
343- * @throws InvalidResponseStatusCodeException
334+ * @throws StorageException
344335 * @throws TooManySaveRetriesException
345336 */
346337 protected function removeLock (): void
@@ -362,7 +353,7 @@ protected function removeLock(): void
362353 *
363354 * @param int $time
364355 * @return bool
365- * @throws InvalidResponseStatusCodeException
356+ * @throws StorageException
366357 * @throws TooManySaveRetriesException
367358 */
368359 protected function addOrUpdateLock (int $ time ): bool
@@ -389,8 +380,9 @@ protected function addOrUpdateLock(int $time): bool
389380 * changed since the last update, they will be updated by this function again.
390381 *
391382 * @return bool
392- * @throws InvalidResponseStatusCodeException
383+ * @throws StorageException
393384 * @throws TooManySaveRetriesException
385+ * @throws Exception
394386 */
395387 protected function saveLocks (): bool
396388 {
@@ -408,9 +400,9 @@ protected function saveLocks(): bool
408400 if (count ($ this ->locks ) === 0 ) {
409401 for ($ i = 1 ; $ i <= static ::$ maxUnavailableRetries ; $ i ++) {
410402 try {
411- $ result = static ::getClient ()->deleteIf ($ this ->etcdKey , $ previousLocks , !$ delayRetry );
403+ $ result = static ::getStorage ()->deleteIf ($ this ->etcdKey , $ previousLocks , !$ delayRetry );
412404 break ;
413- } catch (UnavailableException | DeadlineExceededException | UnknownException $ e ) {
405+ } catch (StorageException $ e ) {
414406 if ($ i === static ::$ maxUnavailableRetries ) {
415407 throw $ e ;
416408 } else {
@@ -424,9 +416,9 @@ protected function saveLocks(): bool
424416
425417 for ($ i = 1 ; $ i <= static ::$ maxUnavailableRetries ; $ i ++) {
426418 try {
427- $ result = static ::getClient ()->putIf ($ this ->etcdKey , $ lockString , $ previousLocks , !$ delayRetry );
419+ $ result = static ::getStorage ()->putIf ($ this ->etcdKey , $ lockString , $ previousLocks , !$ delayRetry );
428420 break ;
429- } catch (UnavailableException | DeadlineExceededException | UnknownException $ e ) {
421+ } catch (StorageException $ e ) {
430422 if ($ i === static ::$ maxUnavailableRetries ) {
431423 throw $ e ;
432424 } else {
@@ -479,17 +471,18 @@ protected function canLock(): bool
479471 /**
480472 * Update the locks array from etcd
481473 *
482- * @throws InvalidResponseStatusCodeException
483474 * @return $this
475+ * @throws StorageException
476+ * @throws Exception
484477 */
485478 public function update (): static
486479 {
487480 $ etcdLockString = false ;
488481 for ($ i = 1 ; $ i <= static ::$ maxUnavailableRetries ; $ i ++) {
489482 try {
490- $ etcdLockString = static ::getClient ()->get ($ this ->etcdKey );
483+ $ etcdLockString = static ::getStorage ()->get ($ this ->etcdKey );
491484 break ;
492- } catch (UnavailableException | DeadlineExceededException | UnknownException $ e ) {
485+ } catch (StorageException $ e ) {
493486 if ($ i === static ::$ maxUnavailableRetries ) {
494487 throw $ e ;
495488 } else {
@@ -524,7 +517,7 @@ protected function updateFromString(string|bool $lockString): static
524517 /**
525518 * Break the lock on destruction of this object
526519 *
527- * @throws InvalidResponseStatusCodeException
520+ * @throws StorageException
528521 * @throws TooManySaveRetriesException
529522 */
530523 public function __destruct ()
0 commit comments