php uses the ordered set zset of redis to implement delay queue

Keywords: Programming Redis PHP Laravel kafka

Delay queue is a message queue with delay function. Compared with ordinary queue, it can consume messages at a specified time.

Application scenario of delay queue:

1. New users sign up, and send e-mails or on-site letters in 10 minutes.

2. After the user places an order, the order will be automatically voided if the payment is not made within 30 minutes.

We use the ordered set zset of redis to realize a simple delay queue, serialize the message data as the value of zset, and take the message processing time as the score. Each time we get a message through zRangeByScore for processing.

<?php
 
class DelayQueue
{
    protected $prefix = 'delay_queue:';
    protected $redis = null;
    protected $key = '';
 
    public function __construct($queue, $config = [])
    {
        $this->key = $this->prefix . $queue;
        $this->redis = new Redis();
        $this->redis->connect($config['host'], $config['port'], $config['timeout']);
        $this->redis->auth($config['auth']);
    }
 
    public function delTask($value)
    {
        return $this->redis->zRem($this->key, $value);
    }
 
    public function getTask()
    {
        //Get the task, take 0 and current time as the interval, and return a record
        return $this->redis->zRangeByScore($this->key, 0, time(), ['limit' => [0, 1]]);
    }
 
    public function addTask($name, $time, $data)
    {
        //Add tasks, with time as the score, and sort the task queue by time from small to large
        return $this->redis->zAdd(
            $this->key,
            $time,
            json_encode([
                'task_name' => $name,
                'task_time' => $time,
                'task_params' => $data,
            ], JSON_UNESCAPED_UNICODE)
        );
    }
 
    public function run()
    {
        //Take only one task at a time
        $task = $this->getTask();
        if (empty($task)) {
            return false;
        }
 
        $task = $task[0];
        //There is the possibility of concurrency. Here, the zrem return value is used to determine who gets the task
        if ($this->delTask($task)) {
            $task = json_decode($task, true);
 
            //Processing tasks
            echo 'Tasks:' . $task['task_name'] . ' Run time:' . date('Y-m-d H:i:s') . PHP_EOL;
 
            return true;
        }
 
        return false;
    }
}
 
$dq = new DelayQueue('close_order', [
    'host' => '127.0.0.1',
    'port' => 6379,
    'auth' => '',
    'timeout' => 60,
]);
 
$dq->addTask('close_order_111', time() + 30, ['order_id' => '111']);
$dq->addTask('close_order_222', time() + 60, ['order_id' => '222']);
$dq->addTask('close_order_333', time() + 90, ['order_id' => '333']);

Then, we write a php script to handle the tasks in the queue.

<?php
 
set_time_limit(0);
 
$dq = new DelayQueue('close_order', [
    'host' => '127.0.0.1',
    'port' => 6379,
    'auth' => '',
    'timeout' => 60,
]);
 
while (true) {
    $dq->run();
    usleep(100000);
}

I hope that the above content can help you. Many PHPer will encounter some problems and bottlenecks when they are advanced. There is no sense of direction when they write too much business code. I don't know where to start to improve. I have collated some information about this, including but not limited to: distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, laravel, YII2, Redis, Swoo For advanced advanced dry goods of multiple knowledge points, such as Le, Swoft, Kafka, Mysql optimization, shell script, Docker, microservice, Nginx, etc., you can share them for free, Please stamp here if you need

Posted by DJP1986 on Sat, 21 Mar 2020 10:15:02 -0700