Swoft 源碼剖析 - 代碼自動更新機制

做者:bromine
連接:https://www.jianshu.com/p/e63...
來源:簡書
著做權歸做者全部,本文已得到做者受權轉載,並對原文進行了從新的排版。
Swoft Github: https://github.com/swoft-clou...php

前言

不一樣於PHP-FPM每次請求都會加載一次PHP代碼,常駐型應用只會讀取一次源文件,爲了不每次發佈/調試代碼都須要手動重啓Swoft應用,Swoft提供了自動重載代碼的功能。git

文件重載管理進程

Swoft註冊了一個名爲reload的Process,該進程會在系統引導的最後一個階段,即Swoole啓動前啓動。該Process會啓動名爲reload的Beangithub

//Swoft\Process\Bootstrap\Process\ReloadProcess.php
/**
 * Relaod process
 *
 * @Process(name="reload", boot=true)
 */
class ReloadProcess implements ProcessInterface
{
    /**
     * @param \Swoft\Process\Process $process
     */
    public function run(SwoftProcess $process)
    {
        $pname = App::$server->getPname();
        $processName = sprintf('%s reload process', $pname);
        $process->name($processName);

        /* @var \Swoft\Process\Bootstrap\Reload $relaod */
        $relaod = App::getBean(Reload::class);
        $relaod->run();
    }
    //.....
}

文件更新監聽Bean

//\Swoft\Process\Bootstrap\Reload::class
/**
 *  @Bean()
 */
class Reload
{
    //code .....

    /**
     * 啓動監聽
     */
    public function run()
    {
        $server = App::$server;
        while (true) {
            sleep($this->interval);
            //FileHelper::md5File()負責遞歸的計算文件夾的md5,其實更名爲FileHelper::md5Dir()更合適,由於他不接受非目錄的文件做爲參數
            $md5File = FileHelper::md5File($this->watchDir);//$this->watchDir固定爲@app別名對應的文件夾
            if (strcmp($this->md5File, $md5File) !== 0) {
                echo "Start reloading...\n";
                $server->isRunning();
                //md5和上次不一致就通知swoole重啓服務
                $server->getServer()->reload();
                echo "Reloaded\n";
            }
            $this->md5File = $md5File;
        }
    }
}

代碼自動重載的機制也很簡單,每間隔幾秒遞歸的計算@app目錄下全部php文件的哈希值,發現文件夾的md5和以前的值有差異則通知Swoole重啓worker進程。segmentfault

Swoole WorkerStart事件

Swoole會通知各個worker重啓,觸發Swoole事件WorkerStart,具體的回調事件以下swoole

namespace Swoft\Bootstrap\Server\ServerTrait.php;

/**
 * OnWorkerStart event callback
 *
 * @param Server $server server
 * @param int $workerId workerId
 * @throws \InvalidArgumentException
 */
public function onWorkerStart(Server $server, int $workerId)
{
    // Init Worker and TaskWorker
    $setting = $server->setting;
    $isWorker = false;

    if ($workerId >= $setting['worker_num']) {
        // TaskWorker
        ApplicationContext::setContext(ApplicationContext::TASK);
        ProcessHelper::setProcessTitle($this->serverSetting['pname'] . ' task process');
    } else {
        // Worker
        $isWorker = true;
        ApplicationContext::setContext(ApplicationContext::WORKER);
        ProcessHelper::setProcessTitle($this->serverSetting['pname'] . ' worker process');
    }
    //觸發一個Swoft服務事件```SwooleEvent::ON_START```,其監聽者使用@ServerListener(event=SwooleEvent::ON_START)聲明
    $this->fireServerEvent(SwooleEvent::ON_WORKER_START, [$server, $workerId, $isWorker]);
    //主要是從新掃描加載註解和Bean的重載
    $this->beforeWorkerStart($server, $workerId, $isWorker);
}
Swoft源碼剖析系列目錄: https://segmentfault.com/a/11...
相關文章
相關標籤/搜索