前言:使用的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('[email protected]') ->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.最後特別注意: 隊列處理器是一個常駐的進程並且在內存中保存着已經啓動的應用狀態。因此,它們並不會在啓動後注意到你代碼的更改。所以,在你的重新部署/修改代碼後,請記得 重啓你的隊列處理器!