thinkphp-queue 是thinkphp 官方提供的一个消息队列服务,我们可用它来做一些需要用到队列的功能,如抢购等,也可用它来实现定时任务功能
1、安装
tp5支持的thinkphp-queue版本为2.0.*,3.0以上的版本需要tp6以上的环境
composer 安装代码:composer require topthink/think-queue=2.0.*
2、搭建消息队列的储存环境
使用 Redis [推荐]
安装并启动 Redis 服务
使用数据库 [不推荐]
CREATE TABLE `prefix_jobs` ( `id` int(11) NOT NULL AUTO_INCREMENT, `queue` varchar(255) NOT NULL, //队列名称 `payload` longtext NOT NULL, //数据和指定的消费类信息在这里面 `attempts` tinyint(3) unsigned NOT NULL, //执行的次数 `reserved` tinyint(3) unsigned NOT NULL, //0未执行 1执行中 `reserved_at` int(10) unsigned DEFAULT NULL, //开始执行的时间戳 `available_at` int(10) unsigned NOT NULL, //最早可执行的时间 `created_at` int(10) unsigned NOT NULL, //创建时间 PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3、消息队列配置
在 站点根目录/config/queue.php中设置配置信息
return [ 'connector' => 'Redis', // Redis 驱动 'expire' => 60, // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null 'default' => 'default', // 默认的队列名称 'host' => '127.0.0.1', // redis 主机ip 'port' => 6379, // redis 端口 'password' => '', // redis 密码 'select' => 0, // 使用哪一个 db,默认为 db0 'timeout' => 0, // redis连接的超时时间 'persistent' => false, // 是否是长连接 // 'connector' => 'Database', // 数据库驱动 // 'expire' => 60, // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null // 'default' => 'default', // 默认的队列名称 // 'table' => 'jobs', // 存储消息的表名,不带前缀 // 'dsn' => [], // 'connector' => 'Topthink', // ThinkPHP内部的队列通知服务平台 ,本文不作介绍 // 'token' => '', // 'project_id' => '', // 'protocol' => 'https', // 'host' => 'qns.topthink.com', // 'port' => 443, // 'api_version' => 1, // 'max_retries' => 3, // 'default' => 'default', // 'connector' => 'Sync', // Sync 驱动,该驱动的实际作用是取消消息队列,还原为同步执行 ];
4、消息队列的创建和推送
在app\index\controller\index中创建方法addHelloJob方法
time(), 'bizId' => uniqid() , 'a' => 1 ] ;
// 4.将该任务推送到消息队列,等待对应的消费者去执行
$isPushed = Queue::push( $jobHandlerClassName , $jobData , $jobQueueName );
// database 驱动时,返回值为 1|false ; redis 驱动时,返回值为 随机字符串|false
if( $isPushed !== false ){
echo date('Y-m-d H:i:s') . " a new Hello Job is Pushed to the MQ"."
";
}else{
echo 'Oops, something went wrong.';
}
}
}
5、消息队列的消费和删除
编写 Hello 消费者类,用于处理 helloJobQueue
队列中的任务
新增 \application\index\job\Hello.php
消费者类,并编写其 fire()
方法
checkDatabaseToSeeIfJobNeedToBeDone($data);
if(!$isJobStillNeedToBeDone){
$job->delete();
return;
}
$isJobDone = $this->doHelloJob($data);
if ($isJobDone) {
// 如果任务执行成功, 记得删除任务
$job->delete();
print("Hello Job has been done and deleted"." \n");
}else{
if ($job->attempts() > 3) {
//通过这个方法可以检查这个任务已经重试了几次了
print("Hello Job has been retried more than 3 times!"." \n");
$job->delete();
// 也可以重新发布这个任务
//print("Hello Job will be availabe again after 2s."." \n");
//$job->release(2); //$delay为延迟时间,表示该任务延迟2秒后再执行
}
}
}
/**
* 有些消息在到达消费者时,可能已经不再需要执行了
* @param array|mixed $data 发布任务时自定义的数据
* @return boolean 任务执行的结果
*/
private function checkDatabaseToSeeIfJobNeedToBeDone($data){
return true;
}
/**
* 根据消息中的数据进行实际的业务处理...
*/
private function doHelloJob($data)
{
print("Hello Job Started. job Data is: ".var_export($data,true)." \n");
print("Hello Job is Fired at " . date('Y-m-d H:i:s') ." \n");
print("Hello Job is Done!"." \n");
return true;
}
}
6、发布任务
在浏览器访问app\index\controller\index中的addHelloJob方法,就会创建一条消息队列信息到队列中
7、消费消息队列
切换到终端项目根目录下执行:php think queue:work --queue helloJobQueue
就会消费掉队列中的一条消息,该命令消费一条消息后就会退出执行,如果想消费者类一直跑着,一有消息发布到队列中就消费。可使用:php think queue:work --queue helloJobQueue --daemon 或者 php think queue:listen --queue helloJobQueue
8、 消息的延迟执行与定时执行
延迟执行,相对于即时执行,是用来限制某个任务的最早可执行时刻。在到达该时刻之前,该任务会被跳过。
可以利用该功能实现定时任务。
使用方式:
// 即时执行 $isPushed = Queue::push($jobHandlerClassName, $jobDataArr, $jobQueueName); // 延迟 2 秒执行 $isPushed = Queue::later( 2, $jobHandlerClassName, $jobDataArr, $jobQueueName); // 延迟到 2017-02-18 01:01:01 时刻执行 $time2wait = strtotime('2017-02-18 01:01:01') - strtotime('now'); $isPushed = Queue::later($time2wait,$jobHandlerClassName, $jobDataArr, $jobQueueName);
// 重发,即时执行 $job->release(); // 重发,延迟 2 秒执行 $job->release(2); // 延迟到 2017-02-18 01:01:01 时刻执行 $time2wait = strtotime('2017-02-18 01:01:01') - strtotime('now'); $job->release($time2wait);
8、实现计划任务
1、任务如订单超时回收,可在每次下单时发布一条消息到队列中,设置好延迟执行时间,在消费者类中查到相应的订单id并做相应的操作
2、第二种方法,发布一条消息,延迟5分钟执行,在消费者类中将所有超时未付款的订单作废,在重发此消息任务
更详细细节参考:https://github.com/coolseven/notes/blob/master/thinkphp-queue/README.md