tp 队列分享
一、安装queue扩展,有的下载后框架可能自带queue扩展。
composer require topthink/think-queue
"repositories": { "packagist": { "type": "composer", "url": "https://packagist.org" } }
二、配置(服务器需要安装有redis):
配置文件位于 application/extra/queue.php
return [ // 'connector' => 'Sync' 'connector' => 'Redis', // Redis 驱动 'expire' => 60, // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null 'default' => 'default', // 默认的队列名称 'host' => '127.0.0.1', // redis 主机ip 'port' => 6379, // redis 端口 'password' => '', // redis 密码 'select' => 1, // 使用哪一个 db,默认为 db0 'timeout' => 0, // redis连接的超时时间 'persistent' => false, // 是否是长连接 ];
三、代码:
创建一个控制器,执行队列里的任务,例如创建一个app\message\controller\DoJob.php。
<?php
/**
* 文件路径: \application\index\job\Hello.php
* 这是一个消费者类,用于处理 helloJobQueue 队列中的任务
*/
namespace app\job;
use think\queue\Job;
use think\Db;
class Test {
/**
* fire方法是消息队列默认调用的方法
* @param Job $job 当前的任务对象
* @param array|mixed $data 发布任务时自定义的数据
*/
public function fire(Job $job,$data){
$userId = isset($data['userId'])?$data['userId']:'';
$id=isset($data['id'])?$data['id']:'';
$episode=isset($data['episode'])?$data['episode']:'';
$progress=isset($data['progress'])?$data['progress']:'';
if(strpos($id,',')) {
$to_ids=explode(',',$id);
foreach($to_ids as $v) {
Db::name('history_film')->insert(['user_id'=>$userId,'video_id'=>$v,'episode_id'=>$episode,'create_time'=>time(),'update_time'=>time()]);
}
$job->delete();
return;
}
if(Db::name('history_film')->where(['user_id'=>$userId,'video_id'=>$id,'episode_id'=>$episode])->find()) {
Db::name('history_film')->where(['user_id'=>$userId,'video_id'=>$id,'episode_id'=>$episode])->update(['progress'=>$progress,'update_time'=>time()]);
Db::name('history_all')->where(['user_id'=>$userId,'video_id'=>$id,'episode_id'=>$episode])->update(['progress'=>$progress,'update_time'=>time()]);
} else {
$data = ['user_id'=>$userId,'video_id'=>$id,'episode_id'=>$episode,'create_time'=>time(),'update_time'=>time()];
Db::name('history_film')->insert($data);
$data = ['user_id'=>$userId,'video_id'=>$id,'episode_id'=>$episode,'type'=>1,'create_time'=>time(),'update_time'=>time()];
Db::name('history_all')->insert($data);
}
$job->delete();
return;
// 如有必要,可以根据业务需求和数据库中的最新数据,判断该任务是否仍有必要执行.
// $isJobStillNeedToBeDone = $this->checkDatabaseToSeeIfJobNeedToBeDone($data);
// if(!$isJobStillNeedToBeDone){
// $job->delete();
// return;
// }
// $isJobDone = $this->doHelloJob($data);
// if ($isJobDone) {
// //如果任务执行成功, 记得删除任务
// $job->delete();
// }else{
// if ($job->attempts() > 3) {
// //通过这个方法可以检查这个任务已经重试了几次了
// $job->delete();
// // 也可以重新发布这个任务
// //$job->release(2); //$delay为延迟时间,表示该任务延迟2秒后再执行
// }
// }
}
/**
* 有些消息在到达消费者时,可能已经不再需要执行了
* @param array|mixed $data 发布任务时自定义的数据
* @return boolean 任务执行的结果
*/
private function checkDatabaseToSeeIfJobNeedToBeDone($data){
return true;
}
/**
* 根据消息中的数据进行实际的业务处理
* @param array|mixed $data 发布任务时自定义的数据
* @return boolean 任务执行的结果
*/
private function doHelloJob($data) {
// 根据消息中的数据进行实际的业务处理...
// test
if (!empty($data)) {
}
return true;
}
}
发布任务到队列中,创建一个测试代码,例如创建一个app\message\controller\addJob.php:
<?php
/**
* Created by PhpStorm.
* User: apple
* Date: 2021/5/16
* Time: 下午10:22
*/
namespace app\shell\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
use aliopensearch\AliOpenSearch;
use think\cache\driver\Redis;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Airec\Airec;
use AlibabaCloud\OpenSearch\OpenSearch;
use api\user\model\VideoModel;
use api\user\model\VideoAllModel;
use OpenSearch\Client\DocumentClient;
use OpenSearch\Client\SearchClient;
use OpenSearch\Util\SearchParamsBuilder;
use OpenSearch\Client\OpenSearchClient;
use think\Queue;
class Queue extends Command
{
protected function configure()
{
parent::configure();
$this->setName('Test')->setDescription('Test');
}
protected function execute(Input $input, Output $output)
{
//任务执行类(消费者消费的处理逻辑)
$jobHandlerClassName = "app\job\Test@fire";
//队列名,如不存在会自动创建
$jobQueueName = "helloJobQueue";
//推送的业务数据
// $jobData = [ 'name' => 'test'.rand(), 'password'=>rand()];
$jobData = [
"userId"=> 1,
"id"=> 1,
"episode"=> 1,
"progress"=> 400,
];
//延迟推送,推送后等待消费者消费
// $isPushed = Queue::later(300, $jobHandlerClassName , $jobData , $jobQueueName );
//立即推送,等待消费者消费
$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"."<br>";
}else{
echo 'Oops, something went wrong.';
}
echo "同步成功";
}
}
四、监听任务并执行
在服务器上,执行框架的根目录下的think命令:
nohup /usr/local/bin/php /home/www/tp5/think queue:work --daemon --queue JobQueue &