Home > Article > Backend Development > Implementation of Swoole custom project initialization event handling
Recently using the imi framework developed based on Swoole to develop a project, I encountered a requirement, which is to do project initialization processing. You don't want Swoole to handle the request before the initialization process is completed. Because there may be some values that are not loaded in, there is a high possibility of problems processing the request.
The thinking process and demo code for solving the problem are given below.
First of all, after analysis, Swoole runs in multi-process mode and is divided into Master
, Manager
, Worker
processes.
The Master process is the process where the cli command file where we start the service is located. There is a problem with the initialization here. All loaded classes and global variables can be used in other Worker processes and cannot be hot restarted to take effect.
The situation of the Manager process is basically the same as above.
Then only the Worker process does the processing, but if it is written in the WorkerStart event, each Worker process will execute it.
<strong>WorkerStart</strong>
Event definition:
function onWorkerStart(swoole_server $server, int $worker_id);
$worker_id is a number between 0-$worker_num, indicating If the ID of this Worker process is
, then this is easy to handle. Directly determine if the workerid is 0 to trigger the project initialization event. The remaining question is how to prevent all Worker processes from processing requests until the initialization execution is completed.
Thinked about it and tried it. This problem can be solved by hanging the coroutine. The demo code is as follows:
<?php use 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); } }
By judging whether the initialization is completed in the request event, if the initialization is not completed, hang Start the current coroutine and add the coroutine ID to the global variable.
After the 0th worker process completes the initialization, it wakes up the suspended coroutines by sending messages to other worker processes. The requests that came in during the initialization period will be executed at this time.
The above is the detailed content of Implementation of Swoole custom project initialization event handling. For more information, please follow other related articles on the PHP Chinese website!