@@ -41,6 +41,13 @@ class RedisQueueDriver implements IQueueDriver
4141 */
4242 protected $ name ;
4343
44+ /**
45+ * 循环尝试 pop 的时间间隔,单位:秒
46+ *
47+ * @var float
48+ */
49+ protected $ timespan = 0.03 ;
50+
4451 public function __construct (string $ name , array $ config = [])
4552 {
4653 $ this ->name = $ name ;
@@ -162,65 +169,87 @@ public function push(IMessage $message, float $delay = 0, array $options = []):
162169
163170 /**
164171 * 从队列弹出一个消息
165- *
172+ *
173+ * @param float $timeout 超时时间,单位:秒。值是-1时立即返回结果
166174 * @return \Imi\Queue\Contract\IMessage|null
167175 */
168- public function pop (): ?IMessage
176+ public function pop (float $ timeout = - 1 ): ?IMessage
169177 {
170- $ this ->parseDelayMessages ();
171- $ this ->parseTimeoutMessages ();
172- $ redis = RedisManager::getInstance ($ this ->poolName );
173- $ result = $ redis ->evalEx (<<<LUA
174- -- 从列表弹出
175- local messageId = redis.call('lpop', KEYS[1])
176- if false == messageId then
177- return -1
178- end
179- -- 获取消息内容
180- local hashResult = redis.call('hgetall', KEYS[3] .. messageId)
181- local message = {}
182- for i=1,#hashResult,2 do
183- message[hashResult[i]] = hashResult[i + 1]
184- end
185- -- 加入工作队列
186- local score = tonumber(message.workingTimeout)
187- if nil == score or score <= 0 then
188- score = -1
189- end
190- redis.call('zadd', KEYS[2], ARGV[1] + score, messageId)
191- return hashResult
192- LUA
193- , [
194- $ this ->getQueueKey (QueueType::READY ),
195- $ this ->getQueueKey (QueueType::WORKING ),
196- $ this ->getMessageKeyPrefix (),
197- microtime (true ),
198- ], 3 );
199-
200- if (-1 === $ result )
201- {
202- return null ;
203- }
204- if (false === $ result )
205- {
206- if ('' === ($ error = $ redis ->getLastError ()))
178+ $ time = $ useTime = 0 ;
179+ do {
180+ if ($ timeout > 0 )
207181 {
208- throw new QueueException ('Queue pop failed ' );
182+ if ($ time )
183+ {
184+ $ leftTime = $ timeout - $ useTime ;
185+ if ($ leftTime > $ this ->timespan )
186+ {
187+ usleep ($ this ->timespan * 1000000 );
188+ }
189+ }
190+ else
191+ {
192+ $ time = microtime (true );
193+ }
209194 }
210- else
195+ $ this ->parseDelayMessages ();
196+ $ this ->parseTimeoutMessages ();
197+ $ redis = RedisManager::getInstance ($ this ->poolName );
198+ $ result = $ redis ->evalEx (<<<LUA
199+ -- 从列表弹出
200+ local messageId = redis.call('lpop', KEYS[1])
201+ if false == messageId then
202+ return -1
203+ end
204+ -- 获取消息内容
205+ local hashResult = redis.call('hgetall', KEYS[3] .. messageId)
206+ local message = {}
207+ for i=1,#hashResult,2 do
208+ message[hashResult[i]] = hashResult[i + 1]
209+ end
210+ -- 加入工作队列
211+ local score = tonumber(message.workingTimeout)
212+ if nil == score or score <= 0 then
213+ score = -1
214+ end
215+ redis.call('zadd', KEYS[2], ARGV[1] + score, messageId)
216+ return hashResult
217+ LUA
218+ , [
219+ $ this ->getQueueKey (QueueType::READY ),
220+ $ this ->getQueueKey (QueueType::WORKING ),
221+ $ this ->getMessageKeyPrefix (),
222+ microtime (true ),
223+ ], 3 );
224+ if ($ result > 0 )
211225 {
212- throw new QueueException ('Queue pop failed, ' . $ error );
226+ $ data = [];
227+ $ length = count ($ result );
228+ for ($ i = 0 ; $ i < $ length ; $ i += 2 )
229+ {
230+ $ data [$ result [$ i ]] = $ result [$ i + 1 ];
231+ }
232+ $ message = new Message ;
233+ $ message ->loadFromArray ($ data );
234+ return $ message ;
213235 }
214- }
215- $ data = [];
216- $ length = count ($ result );
217- for ($ i = 0 ; $ i < $ length ; $ i += 2 )
218- {
219- $ data [$ result [$ i ]] = $ result [$ i + 1 ];
220- }
221- $ message = new Message ;
222- $ message ->loadFromArray ($ data );
223- return $ message ;
236+ if (false === $ result )
237+ {
238+ if ('' === ($ error = $ redis ->getLastError ()))
239+ {
240+ throw new QueueException ('Queue pop failed ' );
241+ }
242+ else
243+ {
244+ throw new QueueException ('Queue pop failed, ' . $ error );
245+ }
246+ }
247+ if ($ timeout < 0 )
248+ {
249+ return null ;
250+ }
251+ } while (($ useTime = (microtime (true ) - $ time )) < $ timeout );
252+ return null ;
224253 }
225254
226255 /**
0 commit comments