Maison  >  Article  >  développement back-end  >  Implémentation de la gestion des événements d'initialisation de projet personnalisé Swoole

Implémentation de la gestion des événements d'initialisation de projet personnalisé Swoole

藏色散人
藏色散人avant
2019-06-03 16:59:112854parcourir

En utilisant récemment le framework imi développé sur la base de Swoole pour développer un projet, j'ai rencontré une exigence, qui est d'effectuer un traitement d'initialisation du projet. Vous ne voulez pas que Swoole traite la demande avant la fin du processus d'initialisation. Étant donné que certaines valeurs peuvent ne pas être chargées, il existe un risque élevé de problèmes lors du traitement de la demande.

Le processus de réflexion et le code de démonstration pour résoudre le problème sont donnés ci-dessous.

Tout d'abord, après analyse, Swoole fonctionne en mode multi-processus et est divisé en processus Master, Manager et Worker .

Le processus Master est le processus où se trouve le fichier de commande cli où nous démarrons le service. Il y a un problème avec l'initialisation ici. Toutes les classes chargées et les variables globales peuvent être utilisées dans d'autres processus Worker et ne peuvent pas l'être. redémarré à chaud pour prendre effet.

La situation du processus Manager est fondamentalement la même que ci-dessus.

Ensuite, seul le processus Worker effectue le traitement, mais s'il est écrit dans l'événement WorkerStart, chaque processus Worker l'exécutera.

<strong>WorkerStart</strong> Définition de l'événement :

function onWorkerStart(swoole_server $server, int $worker_id);

$worker_id est un nombre compris entre 0 et $worker_num, indiquant l'ID de ce processus Worker

Ensuite c'est facile à gérer, déterminez directement que l'ID de travail est 0 pour déclencher l'événement d'initialisation du projet. La question restante est de savoir comment empêcher tous les processus Worker de traiter les demandes jusqu'à ce que l'exécution de l'initialisation soit terminée.

J'y ai réfléchi et essayé. Ce problème peut être résolu en suspendant la coroutine. Le code de démonstration est le suivant :

<?php
 
use Swoole\Coroutine;
 
$http = new swoole_http_server(&#39;127.0.0.1&#39;, 8080);
 
$http->on(&#39;WorkerStart&#39;, function(swoole_http_server $server, $workerId){
    $initFlagFile = __DIR__ . &#39;/init.flag&#39;;
    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[&#39;worker_num&#39;]; ++$i)
        {
            $server->sendMessage(&#39;init&#39;, $i);
        }
    }
});
 
$http->on(&#39;PipeMessage&#39;, function(swoole_http_server $server, $srcWorkerId, $data) {
    if(0 === $srcWorkerId && &#39;init&#39; === $data && !defined(&#39;APP_INITED&#39;))
    {
        // 其它worker进程恢复协程
        resumeCos();
    }
});
 
$http->on(&#39;request&#39;, function (swoole_http_request $request, swoole_http_response $response) {
    // 判断未初始化完毕,则挂起协程
    if(!defined(&#39;APP_INITED&#39;))
    {
        $GLOBALS[&#39;WORKER_START_END_RESUME_COIDS&#39;][] = Coroutine::getuid();
        Coroutine::suspend();
    }
    $response->header(&#39;content-type&#39;, &#39;text/html;charset=utf-8&#39;);
    $response->end(&#39;IMI 是一款基于 Swoole 开发的协程 PHP 开发框架,拥有常驻内存、协程异步非阻塞IO等优点。官方网站:<a href="https://imiphp.com" target="_blank">https://imiphp.com</a>&#39;);
});
 
$http->start();
 
/**
 * 处理项目初始化事件,比如这里延时5秒,模拟初始化处理
 *
 * @return void
 */
function initApp()
{
    $count = 5;
    for($i = 0; $i < $count; ++$i)
    {
        echo &#39;initing &#39;, ($i + 1), &#39;/&#39;, $count, PHP_EOL;
        sleep(1);
    }
}
 
/**
 * 恢复协程
 *
 * @return void
 */
function resumeCos()
{
    define(&#39;APP_INITED&#39;, true);
    $coids = $GLOBALS[&#39;WORKER_START_END_RESUME_COIDS&#39;] ?? [];
    fwrite(STDOUT, &#39;suspend co count: &#39; . count($coids) . PHP_EOL);
    foreach($coids as $id)
    {
        Coroutine::resume($id);
    }
}

En jugeant si l'initialisation est terminée dans l'événement de requête, si l'initialisation n'est pas terminée, suspendez Démarrez la coroutine actuelle et ajoutez l'ID de coroutine à la variable globale.

Lorsque le 0ème processus de travail termine l'initialisation, il réveille les coroutines suspendues en envoyant des messages aux autres processus de travail. Les requêtes arrivées pendant la période d'initialisation seront exécutées à ce moment-là.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer