-
Notifications
You must be signed in to change notification settings - Fork 440
Redis New Implementation #585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
4ca285f
a25f83e
b626b11
50379c7
7716a82
3681e17
5615d56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Enqueue\Redis; | ||
|
||
class LuaScripts | ||
{ | ||
/** | ||
* Get the Lua script to migrate expired messages back onto the queue. | ||
* | ||
* KEYS[1] - The queue we are removing messages from, for example: queues:foo:reserved | ||
* KEYS[2] - The queue we are moving messages to, for example: queues:foo | ||
* ARGV[1] - The current UNIX timestamp | ||
* | ||
* @return string | ||
*/ | ||
public static function migrateExpired() | ||
{ | ||
return <<<'LUA' | ||
-- Get all of the messages with an expired "score"... | ||
local val = redis.call('zrangebyscore', KEYS[1], '-inf', ARGV[1]) | ||
|
||
-- If we have values in the array, we will remove them from the first queue | ||
-- and add them onto the destination queue in chunks of 100, which moves | ||
-- all of the appropriate messages onto the destination queue very safely. | ||
if(next(val) ~= nil) then | ||
redis.call('zremrangebyrank', KEYS[1], 0, #val - 1) | ||
|
||
for i = 1, #val, 100 do | ||
redis.call('lpush', KEYS[2], unpack(val, i, math.min(i+99, #val))) | ||
end | ||
end | ||
|
||
return val | ||
LUA; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,12 +21,42 @@ class RedisConsumer implements Consumer | |
*/ | ||
private $context; | ||
|
||
/** | ||
* @var int | ||
*/ | ||
private $retryDelay; | ||
|
||
/** | ||
* @var RedisQueueConsumer | ||
*/ | ||
private $queueConsumer; | ||
|
||
public function __construct(RedisContext $context, RedisDestination $queue) | ||
{ | ||
$this->context = $context; | ||
$this->queue = $queue; | ||
} | ||
|
||
/** | ||
* @return int | ||
*/ | ||
public function getRetryDelay(): ?int | ||
{ | ||
return $this->retryDelay; | ||
} | ||
|
||
/** | ||
* @param int $retryDelay | ||
*/ | ||
public function setRetryDelay(int $retryDelay): void | ||
{ | ||
$this->retryDelay = $retryDelay; | ||
|
||
if ($this->queueConsumer) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think setting retryDelay property is enough. No need to set same value on queue consumer too. (It will be passed as argument to receiveXXX methods). |
||
$this->queueConsumer->setRetryDelay($this->retryDelay); | ||
} | ||
} | ||
|
||
/** | ||
* @return RedisDestination | ||
*/ | ||
|
@@ -40,40 +70,37 @@ public function getQueue(): Queue | |
*/ | ||
public function receive(int $timeout = 0): ?Message | ||
{ | ||
$timeout = (int) ($timeout / 1000); | ||
if (empty($timeout)) { | ||
$timeout = (int) ceil($timeout / 1000); | ||
|
||
if ($timeout <= 0) { | ||
while (true) { | ||
if ($message = $this->receive(5000)) { | ||
return $message; | ||
} | ||
} | ||
} | ||
|
||
if ($result = $this->getRedis()->brpop([$this->queue->getName()], $timeout)) { | ||
return RedisMessage::jsonUnserialize($result->getMessage()); | ||
} | ||
$this->initQueueConsumer(); | ||
|
||
return null; | ||
return $this->queueConsumer->receiveMessage($timeout); | ||
} | ||
|
||
/** | ||
* @return RedisMessage | ||
*/ | ||
public function receiveNoWait(): ?Message | ||
{ | ||
if ($result = $this->getRedis()->rpop($this->queue->getName())) { | ||
return RedisMessage::jsonUnserialize($result->getMessage()); | ||
makasim marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
$this->initQueueConsumer(); | ||
|
||
return null; | ||
return $this->queueConsumer->receiveMessageNoWait($this->queue); | ||
} | ||
|
||
/** | ||
* @param RedisMessage $message | ||
*/ | ||
public function acknowledge(Message $message): void | ||
{ | ||
// do nothing. redis transport always works in auto ack mode | ||
$this->getRedis()->zrem($this->queue->getName().':reserved', $message->getReservedKey()); | ||
} | ||
|
||
/** | ||
|
@@ -83,15 +110,33 @@ public function reject(Message $message, bool $requeue = false): void | |
{ | ||
InvalidMessageException::assertMessageInstanceOf($message, RedisMessage::class); | ||
|
||
// do nothing on reject. redis transport always works in auto ack mode | ||
$this->acknowledge($message); | ||
|
||
if ($requeue) { | ||
$this->context->createProducer()->send($this->queue, $message); | ||
$message = RedisMessage::jsonUnserialize($message->getReservedKey()); | ||
$message->setHeader('attempts', 0); | ||
|
||
if ($message->getTimeToLive()) { | ||
$message->setHeader('expires_at', time() + $message->getTimeToLive()); | ||
} | ||
|
||
$this->getRedis()->lpush($this->queue->getName(), json_encode($message)); | ||
} | ||
} | ||
|
||
private function getRedis(): Redis | ||
{ | ||
return $this->context->getRedis(); | ||
} | ||
|
||
private function initQueueConsumer(): void | ||
{ | ||
if (null === $this->queueConsumer) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we make a RedisQueueConsumer stateless we could move it to the context and pass to real consumers as a dependency. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The init would not be needed. |
||
$this->queueConsumer = new RedisQueueConsumer($this->getRedis(), [$this->queue]); | ||
|
||
if ($this->retryDelay) { | ||
$this->queueConsumer->setRetryDelay($this->retryDelay); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
redeliveryDelay