Swoole 自定义项目初始化事件处理的实现
為什么80%的碼農都做不了架構師?>>> ??
最近使用基于 Swoole 開發的 imi 框架 開發項目,碰到一個需求,就是想要做項目初始化處理。當初始化處理完成前,不想讓 Swoole 處理請求。因為可能有一些值沒有加載進來,處理請求極有可能出現問題。
下面給出了思考過程及解決問題的demo代碼。
首先分析了一下,Swoole 是多進程模式運行的,分為 Master、Manager、Worker 進程。
Master 進程就是我們啟動服務的 cli 命令文件所在進程,在這里面初始化有一個問題,這里所有加載的類、全局變量,其它 Worker 進程里都可以使用,無法熱重啟生效。
Manager 進程的情況基本和上面差不多。
那么只有在 Worker 進程做處理了,但如果寫在 WorkerStart 事件里,每個 Worker 進程都會去執行。
WorkerStart 事件定義:
function onWorkerStart(swoole_server $server, int $worker_id);
$worker_id是一個從0-$worker_num之間的數字,表示這個Worker進程的ID
那這個就好辦了,直接判斷workerid為0的去觸發項目初始化事件。剩下還有一個問題就是,如何在初始化執行完成前,讓所有 Worker 進程暫時都不處理請求。
思考并嘗試了一下,這個問題可以通過協程掛起來解決,demo 代碼如下:
<?phpuse Swoole\Coroutine;$http = new swoole_http_server('127.0.0.1', 8080);$http->on('WorkerStart', function(swoole_http_server $server, $workerId){$initFlagFile = __DIR__ . '/init.flag';if(0 === $server->worker_id && (!is_file($initFlagFile) || file_get_contents($initFlagFile) != $server->manager_pid)){// 處理項目初始化事件initApp();// 寫入文件,保證不再重復觸發項目初始化事件file_put_contents($initFlagFile, $server->manager_pid);// 當前worker進程恢復協程resumeCos();// 通知其它worker進程for($i = 1; $i < $server->setting['worker_num']; ++$i){$server->sendMessage('init', $i);}} });$http->on('PipeMessage', function(swoole_http_server $server, $srcWorkerId, $data) {if(0 === $srcWorkerId && 'init' === $data && !defined('APP_INITED')){// 其它worker進程恢復協程resumeCos();} });$http->on('request', function (swoole_http_request $request, swoole_http_response $response) {// 判斷未初始化完畢,則掛起協程if(!defined('APP_INITED')){$GLOBALS['WORKER_START_END_RESUME_COIDS'][] = Coroutine::getuid();Coroutine::suspend();}$response->header('content-type', 'text/html;charset=utf-8');$response->end('IMI 是一款基于 Swoole 開發的協程 PHP 開發框架,擁有常駐內存、協程異步非阻塞IO等優點。官方網站:<a href="https://imiphp.com" target="_blank">https://imiphp.com</a>'); });$http->start();/*** 處理項目初始化事件,比如這里延時5秒,模擬初始化處理** @return void*/ function initApp() {$count = 5;for($i = 0; $i < $count; ++$i){echo 'initing ', ($i + 1), '/', $count, PHP_EOL;sleep(1);} }/*** 恢復協程** @return void*/ function resumeCos() {define('APP_INITED', true);$coids = $GLOBALS['WORKER_START_END_RESUME_COIDS'] ?? [];fwrite(STDOUT, 'suspend co count: ' . count($coids) . PHP_EOL);foreach($coids as $id){Coroutine::resume($id);} }通過在 request 事件中判斷是否初始化完畢,如果沒有初始化完成,則掛起當前協程,將協程ID加入全局變量。
當第0個 worker 進程執行完初始化后,通過向其他 worker 進程發送消息,喚醒曾經掛起的協程們,在初始化期間進來的請求,這時候會被執行。
轉載于:https://my.oschina.net/yurun/blog/2050809
總結
以上是生活随笔為你收集整理的Swoole 自定义项目初始化事件处理的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu server 16.10
- 下一篇: 思考 | 人工智能时代:AI芯片能否实现