前言:使用的php框架版本为:thinkphp 5.0.24,队列使用的拓展包为:topthink/think-queue:2.0.3,redis版本为 5.0.5。
- 因为下面提到的队列使用的redis,所以先把这部分安装配置好,想了解的可以参考我之前写的两篇文章:redis入门-安装一、redis入门-php拓展二。
- 在项目根目录下运行composer命令:
composer require topthink/think-queue:"2.0.3"
-
如果安装没问题的话,那么可以进行下一步。系统生成了配置文件:\application\extra\queue.php,我们修改为:
<?php return [ //redis 'connector'=>'redis', 'expire' => 0, 'default' => 'default', 'host' => '127.0.0.1', 'port' => 6379, 'password' => '', 'select' => 0, 'timeout' => 0, '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 驱动,该驱动的实际作用是取消消息队列,还原为同步执行 ];
-
自己项目中的业务代码
public function sendEmail() { //业务代码....获取到邮件账号,然后加入到队列,这里方便测试,临时用input获取具体邮件 $email = input('param.email'); $return = $this->mailTask($email);//mailTask为邮件队列 if($return){ $this->success('发送成功'); } $this->error('发送失败'); } //邮件队列 private function mailTask($email ='') { $jobHandlerClassName = 'app\index\job\SendEmail';//负责处理队列任务的类 $jobQueueName = "sendEmailQueue";//队列名称 $jobData = ['email' => $email];//当前任务的业务数据 $isPushed = Queue::push($jobHandlerClassName , $jobData , $jobQueueName );//将该任务推送到消息队列 if($isPushed !== false ){ return true; // echo date('Y-m-d H:i:s') . '邮件队列任务发送成功'; }else{ return false; // echo date('Y-m-d H:i:s') . '邮件队列发送失败'; } }
-
消息的消费与删除 ,用于处理 sendEmail
Queue
队列中的任务,路径在\application\index\job\SendEmail.php,这里用的邮件发送你可以使用别的第三方拓展包,如:phpmailer,我之前也记录过使用:邮件功能-phpmailer。<?php /** * 这是一个消费者类,用于处理队列中的任务 */ namespace app\index\job; use think\queue\Job; use app\common\library\Email; use think\Exception; class SendEmail { /** * fire方法是消息队列默认调用的方法 * @param Job $job 当前的任务对象 * @param array|mixed $data 发布任务时自定义的数据 */ public function fire(Job $job,$data) { // 有些消息在到达消费者时,可能已经不再需要执行了 $isJobStillNeedToBeDone = $this->checkDatabaseToSeeIfJobNeedToBeDone($data); if(!$isJobStillNeedToBeDone){ $job->delete(); return; } //执行发送邮件 $isJobDone = $this->doJob($data); if ($isJobDone) { // 如果任务执行成功,删除任务 print("<warn>邮件队列已执行完成并且已删除!"."</warn>\n"); $job->delete(); }else{ print("<warn>任务执行失败!"."</warn>\n"); if ($job->attempts() > 3) { //通过这个方法可以检查这个任务已经重试了几次了 print("<warn>邮件队列已经重试超过3次,现在已经删除该任务"."</warn>\n"); $job->delete(); }else{ print ("<info>重新执行该任务!第" . $job->attempts() . "次</info>\n"); $job->release(); //重发任务 } } } /** * 该方法用于接收任务执行失败的通知 * @param $data string|array|... 发布任务时传递的数据 */ public function failed($data){ //可以发送邮件给相应的负责人员 $email = new Email; $email->to('adamlyxxx@163.com') ->subject(__('邮件发送任务失败')) ->message('邮件发送任务失败,对方邮箱是:'.$data['email']) ->send(); // print("Warning: Job failed after max retries. job data is :".var_export($data,true)."\n"); } /** * 有些消息在到达消费者时,可能已经不再需要执行了 * @param array|mixed $data 发布任务时自定义的数据 * @return boolean 任务执行的结果 */ private function checkDatabaseToSeeIfJobNeedToBeDone($data){ return true; } /** * 根据消息中的数据进行实际的业务处理... */ private function doJob($data) { $email = new Email; try { $email->to($data['email']) ->subject(__('账号激活邮件')) ->message('这里放内容') ->send(); return true; } catch (Exception $e) { return false; } } }
-
到程序的根目录,命令行执行:
php think queue:work --queue sendEmailQueue
到这里通过队列发送邮件的代码就搞定了;但如果用于生产环境,那么还差一个supervisor。
-
supervisor的安装和配置部分 ,我主要参考了这篇:tp5.1 + think-queue + supervisor,在配置过程遇到了好几个坑,这里是踩到的,作为参考:
2.Centos7.3配置Supervisor遇到的一些小问题
3.另一种方式 安装配置 supervisor
4.记录详细的thinkphp-queue 笔记
5.常用的supervisor命令:supervisor 进程管理
6.最后特别注意: 队列处理器是一个常驻的进程并且在内存中保存着已经启动的应用状态。因此,它们并不会在启动后注意到你代码的更改。所以,在你的重新部署/修改代码后,请记得 重启你的队列处理器!