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,15 +73,22 @@ 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 ) {
60
- list ($ id , $ message , $ ttr , $ attempt ) = $ payload ;
61
- if ($ this ->handleMessage ($ id , $ message , $ ttr , $ attempt )) {
62
- $ this ->delete ($ id );
76
+ if ($ this ->acquire ()) {
77
+ if (($ payload = $ this ->reserve ($ timeout )) !== null ) {
78
+ list ($ id , $ message , $ ttr , $ attempt ) = $ payload ;
79
+ if ($ this ->handleMessage ($ id , $ message , $ ttr , $ attempt )) {
80
+ $ this ->delete ($ id );
81
+ }
82
+
83
+ } elseif (!$ repeat ) {
84
+ break ;
63
85
}
64
- } elseif (! $ repeat ) {
65
- break ;
86
+
87
+ $ this -> release () ;
66
88
}
67
89
}
90
+
91
+ $ this ->release ();
68
92
});
69
93
}
70
94
@@ -95,10 +119,15 @@ public function status($id)
95
119
*/
96
120
public function clear ()
97
121
{
98
- while (!$ this ->redis -> set ( " $ this -> channel .moving_lock " , true , ' NX ' )) {
122
+ while (!$ this ->acquire ( 0 )) {
99
123
usleep (10000 );
100
124
}
101
- $ this ->redis ->executeCommand ('DEL ' , $ this ->redis ->keys ("$ this ->channel .* " ));
125
+
126
+ try {
127
+ $ this ->redis ->executeCommand ('DEL ' , $ this ->redis ->keys ("$ this ->channel .* " ));
128
+ } finally {
129
+ $ this ->release ();
130
+ }
102
131
}
103
132
104
133
/**
@@ -110,19 +139,25 @@ public function clear()
110
139
*/
111
140
public function remove ($ id )
112
141
{
113
- while (!$ this ->redis -> set ( " $ this -> channel .moving_lock " , true , ' NX ' , ' EX ' , 1 )) {
142
+ while (!$ this ->acquire ( 0 )) {
114
143
usleep (10000 );
115
144
}
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
145
122
- return true ;
123
- }
146
+ try {
147
+ if ($ this ->redis ->hdel ("$ this ->channel .messages " , $ id )) {
148
+ $ this ->redis ->zrem ("$ this ->channel .delayed " , $ id );
149
+ $ this ->redis ->zrem ("$ this ->channel .reserved " , $ id );
150
+ $ this ->redis ->lrem ("$ this ->channel .waiting " , 0 , $ id );
151
+ $ this ->redis ->hdel ("$ this ->channel .attempts " , $ id );
152
+
153
+ return true ;
154
+ }
155
+
156
+ return false ;
124
157
125
- return false ;
158
+ } finally {
159
+ $ this ->release ();
160
+ }
126
161
}
127
162
128
163
/**
@@ -131,11 +166,9 @@ public function remove($id)
131
166
*/
132
167
protected function reserve ($ timeout )
133
168
{
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
- }
169
+ // Moves delayed and reserved jobs into waiting list
170
+ $ this ->moveExpired ("$ this ->channel .delayed " );
171
+ $ this ->moveExpired ("$ this ->channel .reserved " );
139
172
140
173
// Find a new waiting message
141
174
$ id = null ;
@@ -201,4 +234,27 @@ protected function pushMessage($message, $ttr, $delay, $priority)
201
234
202
235
return $ id ;
203
236
}
237
+
238
+ /**
239
+ * Acquire the lock.
240
+ *
241
+ * @return boolean
242
+ */
243
+ protected function acquire ($ timeout = null )
244
+ {
245
+ $ timeout = $ timeout !== null ? $ timeout : $ this ->mutexTimeout ;
246
+
247
+ return $ this ->mutex ->acquire (__CLASS__ . $ this ->channel , $ timeout );
248
+ }
249
+
250
+ /**
251
+ * Release the lock.
252
+ *
253
+ * @return boolean
254
+ */
255
+ protected function release ()
256
+ {
257
+ return $ this ->mutex ->release (__CLASS__ . $ this ->channel );
258
+ }
259
+
204
260
}
0 commit comments