12
12
use yii \di \Instance ;
13
13
use yii \queue \cli \Queue as CliQueue ;
14
14
use yii \redis \Connection ;
15
+ use yii \redis \Mutex ;
15
16
16
17
/**
17
18
* Redis Queue.
@@ -24,10 +25,25 @@ class Queue extends CliQueue
24
25
* @var Connection|array|string
25
26
*/
26
27
public $ redis = 'redis ' ;
28
+
29
+ /**
30
+ * @var Mutex|array|string
31
+ */
32
+ public $ mutex = [
33
+ 'class ' => Mutex::class,
34
+ 'redis ' => 'redis ' ,
35
+ ];
36
+
37
+ /**
38
+ * @var integer
39
+ */
40
+ public $ mutexTimeout = 3 ;
41
+
27
42
/**
28
43
* @var string
29
44
*/
30
45
public $ channel = 'queue ' ;
46
+
31
47
/**
32
48
* @var string command class name
33
49
*/
@@ -41,6 +57,7 @@ public function init()
41
57
{
42
58
parent ::init ();
43
59
$ this ->redis = Instance::ensure ($ this ->redis , Connection::class);
60
+ $ this ->mutex = Instance::ensure ($ this ->mutex , Mutex::class);
44
61
}
45
62
46
63
/**
@@ -56,11 +73,14 @@ public function run($repeat, $timeout = 0)
56
73
{
57
74
return $ this ->runWorker (function (callable $ canContinue ) use ($ repeat , $ timeout ) {
58
75
while ($ canContinue ()) {
59
- if (($ payload = $ this ->reserve ($ timeout )) !== null ) {
76
+ if ($ this -> acquire () && ($ payload = $ this ->reserve ($ timeout )) !== null ) {
60
77
list ($ id , $ message , $ ttr , $ attempt ) = $ payload ;
61
78
if ($ this ->handleMessage ($ id , $ message , $ ttr , $ attempt )) {
62
79
$ this ->delete ($ id );
63
80
}
81
+
82
+ $ this ->release ();
83
+
64
84
} elseif (!$ repeat ) {
65
85
break ;
66
86
}
@@ -95,10 +115,15 @@ public function status($id)
95
115
*/
96
116
public function clear ()
97
117
{
98
- while (!$ this ->redis -> set ( " $ this -> channel .moving_lock " , true , ' NX ' )) {
118
+ while (!$ this ->acquire ( 0 )) {
99
119
usleep (10000 );
100
120
}
101
- $ this ->redis ->executeCommand ('DEL ' , $ this ->redis ->keys ("$ this ->channel .* " ));
121
+
122
+ try {
123
+ $ this ->redis ->executeCommand ('DEL ' , $ this ->redis ->keys ("$ this ->channel .* " ));
124
+ } finally {
125
+ $ this ->release ();
126
+ }
102
127
}
103
128
104
129
/**
@@ -110,19 +135,25 @@ public function clear()
110
135
*/
111
136
public function remove ($ id )
112
137
{
113
- while (!$ this ->redis -> set ( " $ this -> channel .moving_lock " , true , ' NX ' , ' EX ' , 1 )) {
138
+ while (!$ this ->acquire ( 0 )) {
114
139
usleep (10000 );
115
140
}
116
- if ($ this ->redis ->hdel ("$ this ->channel .messages " , $ id )) {
117
- $ this ->redis ->zrem ("$ this ->channel .delayed " , $ id );
118
- $ this ->redis ->zrem ("$ this ->channel .reserved " , $ id );
119
- $ this ->redis ->lrem ("$ this ->channel .waiting " , 0 , $ id );
120
- $ this ->redis ->hdel ("$ this ->channel .attempts " , $ id );
121
141
122
- return true ;
123
- }
142
+ try {
143
+ if ($ this ->redis ->hdel ("$ this ->channel .messages " , $ id )) {
144
+ $ this ->redis ->zrem ("$ this ->channel .delayed " , $ id );
145
+ $ this ->redis ->zrem ("$ this ->channel .reserved " , $ id );
146
+ $ this ->redis ->lrem ("$ this ->channel .waiting " , 0 , $ id );
147
+ $ this ->redis ->hdel ("$ this ->channel .attempts " , $ id );
148
+
149
+ return true ;
150
+ }
151
+
152
+ return false ;
124
153
125
- return false ;
154
+ } finally {
155
+ $ this ->release ();
156
+ }
126
157
}
127
158
128
159
/**
@@ -131,11 +162,9 @@ public function remove($id)
131
162
*/
132
163
protected function reserve ($ timeout )
133
164
{
134
- // Moves delayed and reserved jobs into waiting list with lock for one second
135
- if ($ this ->redis ->set ("$ this ->channel .moving_lock " , true , 'NX ' , 'EX ' , 1 )) {
136
- $ this ->moveExpired ("$ this ->channel .delayed " );
137
- $ this ->moveExpired ("$ this ->channel .reserved " );
138
- }
165
+ // Moves delayed and reserved jobs into waiting list
166
+ $ this ->moveExpired ("$ this ->channel .delayed " );
167
+ $ this ->moveExpired ("$ this ->channel .reserved " );
139
168
140
169
// Find a new waiting message
141
170
$ id = null ;
@@ -201,4 +230,25 @@ protected function pushMessage($message, $ttr, $delay, $priority)
201
230
202
231
return $ id ;
203
232
}
233
+
234
+ /**
235
+ * Acquire the lock.
236
+ *
237
+ * @return boolean
238
+ */
239
+ protected function acquire ($ timeout = null )
240
+ {
241
+ return $ this ->mutex ->acquire (__CLASS__ . $ this ->channel , $ timeout ?? $ this ->mutexTimeout );
242
+ }
243
+
244
+ /**
245
+ * Release the lock.
246
+ *
247
+ * @return boolean
248
+ */
249
+ protected function release ()
250
+ {
251
+ return $ this ->mutex ->release (__CLASS__ . $ this ->channel );
252
+ }
253
+
204
254
}
0 commit comments