1818 *
1919 * @see http://redis.io/topics/distlock
2020 */
21- abstract class AbstractRedlockMutex extends AbstractSpinlockMutex implements LoggerAwareInterface
21+ abstract class AbstractRedlockMutex extends AbstractSpinlockWithTokenMutex implements LoggerAwareInterface
2222{
2323 use LoggerAwareTrait;
2424
2525 /** @var array<int, TClient> */
2626 private array $ clients ;
2727
28- private string $ token ;
29-
3028 /**
31- * The Redis APIs needs to be connected. I.e. Redis::connect() was
29+ * The Redis instance needs to be connected. I.e. Redis::connect() was
3230 * called already.
3331 *
3432 * @param array<int, TClient> $clients
3533 * @param float $acquireTimeout In seconds
34+ * @param float $expireTimeout In seconds
3635 */
37- public function __construct (array $ clients , string $ name , float $ acquireTimeout = 3 )
36+ public function __construct (array $ clients , string $ name , float $ acquireTimeout = 3 , float $ expireTimeout = \ INF )
3837 {
39- parent ::__construct ($ name , $ acquireTimeout );
38+ parent ::__construct ($ name , $ acquireTimeout, $ expireTimeout );
4039
4140 $ this ->clients = $ clients ;
4241 $ this ->logger = new NullLogger ();
4342 }
4443
4544 #[\Override]
46- protected function acquire (string $ key , float $ expire ): bool
45+ protected function acquireWithToken (string $ key , float $ expireTimeout )
4746 {
4847 // 1. This differs from the specification to avoid an overflow on 32-Bit systems.
49- $ time = microtime (true );
48+ $ startTs = microtime (true );
5049
5150 // 2.
5251 $ acquired = 0 ;
5352 $ errored = 0 ;
54- $ this -> token = LockUtil::getInstance ()->makeRandomToken ();
53+ $ token = LockUtil::getInstance ()->makeRandomToken ();
5554 $ exception = null ;
5655 foreach ($ this ->clients as $ index => $ client ) {
5756 try {
58- if ($ this ->add ($ client , $ key , $ this -> token , $ expire )) {
57+ if ($ this ->add ($ client , $ key , $ token , $ expireTimeout )) {
5958 ++$ acquired ;
6059 }
6160 } catch (LockAcquireException $ exception ) {
6261 // todo if there is only one redis server, throw immediately.
6362 $ context = [
6463 'key ' => $ key ,
6564 'index ' => $ index ,
66- 'token ' => $ this -> token ,
65+ 'token ' => $ token ,
6766 'exception ' => $ exception ,
6867 ];
6968 $ this ->logger ->warning ('Could not set {key} = {token} at server #{index} ' , $ context );
@@ -73,16 +72,16 @@ protected function acquire(string $key, float $expire): bool
7372 }
7473
7574 // 3.
76- $ elapsedTime = microtime (true ) - $ time ;
77- $ isAcquired = $ this ->isMajority ($ acquired ) && $ elapsedTime <= $ expire ;
75+ $ elapsedTime = microtime (true ) - $ startTs ;
76+ $ isAcquired = $ this ->isMajority ($ acquired ) && $ elapsedTime <= $ expireTimeout ;
7877
7978 if ($ isAcquired ) {
8079 // 4.
81- return true ;
80+ return $ token ;
8281 }
8382
8483 // 5.
85- $ this ->release ($ key );
84+ $ this ->releaseWithToken ($ key, $ token );
8685
8786 // In addition to RedLock it's an exception if too many servers fail.
8887 if (!$ this ->isMajority (count ($ this ->clients ) - $ errored )) {
@@ -99,7 +98,7 @@ protected function acquire(string $key, float $expire): bool
9998 }
10099
101100 #[\Override]
102- protected function release (string $ key ): bool
101+ protected function releaseWithToken (string $ key, string $ token ): bool
103102 {
104103 /*
105104 * All Redis commands must be analyzed before execution to determine which keys the command will operate on. In
@@ -117,15 +116,15 @@ protected function release(string $key): bool
117116 $ released = 0 ;
118117 foreach ($ this ->clients as $ index => $ client ) {
119118 try {
120- if ($ this ->evalScript ($ client , $ script , [$ key ], [$ this -> token ])) {
119+ if ($ this ->evalScript ($ client , $ script , [$ key ], [$ token ])) {
121120 ++$ released ;
122121 }
123122 } catch (LockReleaseException $ e ) {
124123 // todo throw if there is only one redis server
125124 $ context = [
126125 'key ' => $ key ,
127126 'index ' => $ index ,
128- 'token ' => $ this -> token ,
127+ 'token ' => $ token ,
129128 'exception ' => $ e ,
130129 ];
131130 $ this ->logger ->warning ('Could not unset {key} = {token} at server #{index} ' , $ context );
0 commit comments