redis队列实现
redis队列,使用了list列表数据结构,lpush生成,rpop消费模式。
队列处理命令
yiic queue worker --qname=<queue_name>
<queue_name>是队列的名称,例如:current, position等等, 这只是消费者,即队列处理程序。
这是一个典行的yii的命令行程序,文件在/path/to/protected/commands/queueCommand.php.
调用的是actionWorker方法, yii中的命令行程序也可以看做一种MVC 上面的命令就是控制器操作。
actionWorker方法大致的工作流程如下:
-
取出所有可用的队列名称(列表)
-
将命令行给定的队列名称在列表中对比,如果存在,是继续,否则退出。
-
随机给定一个超时时间,防止卡死(5-20分钟)
-
循环读取指定的队列中的内容,进行处理
队列操作说明
队列核心基础代码,在/path/to/protected/models/Queue.php中,具体做了如下封装
-
putin($params=null, $type=null) 写入队列
-
getit($type) 从队列取出一条
-
getQueueTypeList 获得所有队列名字
putin方法的参数 $params为写入队列的内容,它是一个关联数组,大致的格式如下:
array( 'method'=>'function_name', //指定一个方法名 //(其实这里指定的方法,已经固定到了QueueProcess.php中的方法, //在消费时固定了,当然也可以不固定,可以改造。 'params'=>array( //传给这个方法的参数,目前是将这个params数组做为一个参数传给到了上面指定的方法中。 'name'=>'name' 'pass'=>'pass' ) )
$type参数是队列的名字, (实际在redis中的真实key会在前面加上queue_ 例如:task,则真实的redis中的key是queue_task),底层真实写入redis中的数据是将上面的$params进行json_encode后的字符串存入redis中。
先看一个入队列的程序
$task=array( 'method'=>'driver_current_pos', 'params'=>array( 'lng'=>1.0 'lat'=>1.0 'driver_id'=>'BJ0001' ) ); Queue::model()->putin($task,'current');
再看一个,具体消费处理时的代码,此代码在/path/to/protected/commands/queueCommand.php中的queue_run方法
private function queue_run($task) { //task就是从redis中取出的数据,并已经json decode后的对象了。 $method=$task['method']; $params=$task['params']; echo "\n".$method.':'.json_encode($params); try { $queue_process=new QueueProcess(); //这里使用了一个php的内置方法,进行动态调用 //当然也可以直接写成这样php5.5.3之后可以 //$queue_process->{$method}($params); 这样可能更直观 //php5.5.3之前,只能向下面这样写 call_user_func_array(array( $queue_process, $method ), array( $params )); } catch(Exception $e) { echo "error:$method\n"; print_r($e); } }
那么相对应的队列业务处理的代码,基本上就都在QueueProcess这个类中了,他的位置在/path/to/protected/models/QueueProcess.php.