[原创]Swoft源码剖析-代码自动更新机制

不同于php-fpm每次请求都会加载一次PHP代码,常驻型应用只会读取一次源文件,为了避免每次发布/调试代码都需要手动重启swoft应用,swoft提供了自动重载代码的功能。

文件重载管理进程

swoft注册了一个名为reload的Process,该进程会在系统引导的最后一个阶段,即swoole启动前启动。该Process会启动名为reload的Bean

//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重启work进程。

Swoole WorkerStart事件

swoole会通知各个worker重启,触发swoole事件WorkerStart,具体的回调事件如下

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://www.jianshu.com/p/2f679e0b4d58

你可能感兴趣的:([原创]Swoft源码剖析-代码自动更新机制)