本想自己適配的,奈何keng貌似不少,所以果斷選擇官方提供的包來適配233。。。
默認條件:thinkphp5.1.*版本下,且安裝了swoole擴展
主要演示:task 任務的投遞
友情提示:在swoole啟動框架時,需注意靜態變量的使用,會常駐內存(比如單例的變量),... 無圖言卵,我么的口號是有圖有真相(搞事)
以下是swoole下單例模式發送郵件:
請看收件人, 圖一給 994xxx@qq.com發送郵件; 圖二給 159xxx@qq.com 發送郵件,其收件人卻有兩(包含圖一中的賬號)。
一、安裝
composer require topthink/think-swoole=2.0.*
二、使用
如果你要運行 swoole 的 http 服務器來啟動 thinkPHP框架,執行
php think swoole
默認啟動完成后,會在0.0.0.0:9501啟動一個HTTP Server,可以直接訪問當前的應用。
swoole的參數可以在應用配置目錄下的 swoole.php 里面配置,配置詳情見 thinkPHP官網
擴展中定義了 onWorkerStart
和 onRequest
事件回調方法(如果不熟悉請不要隨意替換),如果你需要自定義swoole
的事件回調方法,可以在配置文件中使用閉包定義。
以下是我的配置(自定義了task任務回調):
use app\common\lib\utils\Task; use think\facade\Env; use think\facade\Log; // +---------------------------------------------------------------------- // | Swoole設置 php think swoole命令行下有效 // +---------------------------------------------------------------------- return [ // 擴展自身配置 'host' => '0.0.0.0', // 監聽地址 'port' => 9501, // 監聽端口 'mode' => '', // 運行模式 默認為SWOOLE_PROCESS 'sock_type' => '', // sock type 默認為SWOOLE_SOCK_TCP 'server_type' => 'http', // 服務類型 支持 http websocket 'app_path' => '', // 應用地址 如果開啟了 'daemonize'=>true 必須設置(使用絕對路徑) 'file_monitor' => false, // 是否開啟PHP文件更改監控(調試模式下自動開啟) 'file_monitor_interval' => 2, // 文件變化監控檢測時間間隔(秒) 'file_monitor_path' => [], // 文件監控目錄 默認監控application和config目錄 // 可以支持swoole的所有配置參數 'pid_file' => Env::get('runtime_path') . 'swoole.pid', 'log_file' => Env::get('runtime_path') . 'swoole.log', 'document_root' => Env::get('root_path') . 'public', 'enable_static_handler' => true, 'timer' => true,//是否開啟系統定時器 'interval' => 500,//系統定時器 時間間隔 'task_worker_num' => 1,//swoole 任務工作進程數量 /** * 自定義投遞任務 * @param swoole_server $serv * @param int $taskId * @param int $srcWorkerId * @param mixed $data */ 'Task' => function($serv, $taskId, $srcWorkerId, $data){ $taskObj = new Task(); $classMethods = get_class_methods(Task::class); if (!in_array($data['method'], $classMethods)) { return 'method:'.$data['method'].' not find in'.Task::class; } return call_user_func_array([$taskObj, $data['method']], $data['params']); }, /** * onTask事件中沒有調用finish方法或者return結果,worker進程不會觸發onFinish * @Param swoole_server $serv * @param int $taskId 任務的ID * @param string $data 任務處理的結果內容 */ 'Finish' => function ($serv, $taskId, $data) { // echo 'taskId:' . $taskId . PHP_EOL; echo 'Finished:' . $data; Log::record($data); } ];
實現任務的投遞兩種方法實現
Index控制器中:
<?php namespace app\index\controller; use app\common\lib\task\SmsTask; use app\common\lib\utils\Tool;use think\Controller; use think\Request; class Index extends Controller {
public function sendSms(Request $request) { $result = $this->validate($request->post(), ['mobile' => 'require|mobile']); if (true !== $result) { return Tool::json('', $result, 250); } $mobile = $request->post('mobile'); // 1、使用topthink/swoole自帶的任務投遞方式,傳遞參數必須是對象或者swoole回調函數 // $smsObj = new SmsTask($mobile); // app('swoole')->task($smsObj); // app('swoole')->task($smsObj); // 2、自定義任務投遞方式 app('swoole')->task(Tool::taskParam('sendSms', (array)$mobile)); return Tool::json('', '短信發送成功'); }
SmsTask.php
使用系統默認的回調模板,
且投遞的參數必須是對象或者swoole回調函數,
投遞任務后默認會執行 run()方法或者swoole回調函數
<?php namespace app\common\lib\task; use Fairy\SmsSender; use think\facade\Config; use think\swoole\template\Task; /** * 使用 topthink/swoole 自帶的Task任務 * Class SmsTask * @package app\common\lib\task */ class SmsTask extends Task { private $mobile; public function initialize($args) { // TODO: Implement initialize() method. $this->mobile = $args[0]; } public function run($serv, $taskId, $fromWorkerId) { // TODO: Implement run() method. $smsObj = SmsSender::getInstance(Config::get('mail.')); $bool = $smsObj->send($this->mobile); if ($bool) { return 'send sms to ' . $this->mobile . ' success'; } else { return $smsObj->getError(); } } }
Task.php
配合swoole.php中自定義的 task 回調函數使用
<?php namespace app\common\lib\utils; use Fairy\SmsSender;use think\facade\Config; /** * 異步任務類 * Class Task * @package app\common\lib\utils */ class Task { /** * 異步發送短信 * @param $mobile * @return mixed|string * @throws \ErrorException */ public function sendSms($mobile) { $smsObj = SmsSender::getInstance(Config::get('sms.')); $bool = $smsObj->send($mobile); if ($bool) { return 'send sms to ' . $mobile . ' success'; } else { return 'send sms to ' . $mobile . ' failed: ' . $smsObj->getError(); } } }
異步發送短信執行流程(拿自定義的task來舉例):
- 配置swoole.php的自定義task函數
- 訪問控制器 index/index/index 下的 sendSms() 方法 會投遞一個任務,傳遞一些參數給task,此時接口數據已返回且短信發送任務也已投遞
- task回調,也就是執行 swoole.php 中的配置的 task 函數
- 執行 finish 回調
- 打完收工,你學會了嗎
參考:
https://www.kancloud.cn/manual/thinkphp5_1/675277