不同于php-fpm每次請求都會(huì)加載一次PHP代碼,常駐型應(yīng)用只會(huì)讀取一次源文件,為了避免每次發(fā)布/調(diào)試代碼都需要手動(dòng)重啟swoft應(yīng)用,swoft提供了自動(dòng)重載代碼的功能。
文件重載管理進(jìn)程
swoft注冊了一個(gè)名為reload的Process,該進(jìn)程會(huì)在系統(tǒng)引導(dǎo)的最后一個(gè)階段,即swoole啟動(dòng)前啟動(dòng)。該P(yáng)rocess會(huì)啟動(dòng)名為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();
}
//.....
}
文件更新監(jiān)聽Bean
//\Swoft\Process\Bootstrap\Reload::class
/**
* @Bean()
*/
class Reload
{
//code .....
/**
* 啟動(dòng)監(jiān)聽
*/
public function run()
{
$server = App::$server;
while (true) {
sleep($this->interval);
//FileHelper::md5File()負(fù)責(zé)遞歸的計(jì)算文件夾的md5,其實(shí)改名為FileHelper::md5Dir()更合適,因?yàn)樗唤邮芊悄夸浀奈募鳛閰?shù)
$md5File = FileHelper::md5File($this->watchDir);//$this->watchDir固定為@app別名對應(yīng)的文件夾
if (strcmp($this->md5File, $md5File) !== 0) {
echo "Start reloading...\n";
$server->isRunning();
//md5和上次不一致就通知swoole重啟服務(wù)
$server->getServer()->reload();
echo "Reloaded\n";
}
$this->md5File = $md5File;
}
}
}
代碼自動(dòng)重載的機(jī)制也很簡單,每間隔幾秒遞歸的計(jì)算@app目錄下所有php文件的哈希值,發(fā)現(xiàn)文件夾的md5和之前的值有差別則通知swoole重啟work進(jìn)程。
Swoole WorkerStart事件
swoole會(huì)通知各個(gè)worker重啟,觸發(fā)swoole事件WorkerStart,具體的回調(diào)事件如下
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');
}
//觸發(fā)一個(gè)Swoft服務(wù)事件```SwooleEvent::ON_START```,其監(jiān)聽者使用@ServerListener(event=SwooleEvent::ON_START)聲明
$this->fireServerEvent(SwooleEvent::ON_WORKER_START, [$server, $workerId, $isWorker]);
//主要是重新掃描加載注解和Bean的重載
$this->beforeWorkerStart($server, $workerId, $isWorker);
}
Swoft源碼剖析系列目錄:http://m.itdecent.cn/p/2f679e0b4d58