laravel框架使用swoole实现代码热更新

之前设计方案

可以看这篇文章

file

swoole热更新官方文档

由于对于laravel框架的认识真的有限,所以有可能不是正确观点,但是技术方案肯定是没错的

导致热更新不成功的致命点

  • 大家可以看到,我是用artisan命令来启动的服务,也就是说,在启动artisan的时候,就载入了autoload
  • 事件绑定到GameMatchController的同时,实例化了GameMatchController,也就是说明在进程启动前你已经载入了GameMatchController这个类,以至于inotify检测到了代码变化,也执行了$server->reload,但是又怎么样呢?你的代码在启动进程前就载入.死都不会给你更新的..相当于这次reload什么代码都没更新😂 😂 😂
    $handle = app()->make(GameMatchController::class);

改进之后方案

设计图

file

Index.php

require 'MatchServer.php';
if (php_sapi_name() != 'cli') die('Please use cli Mode to Start!');
define('ROOT_PATH',dirname(dirname(dirname(__DIR__))).'/');
define('PORT',20005);
$server = new MatchServer();

MatchServer.php

    private $server;
    protected $application;
    function __construct ()
    {
        # 创建websocket
        $this->server = new swoole_websocket_server("0.0.0.0", PORT);
        $this->server->table = $table;

        // 注册回调事件
        $this->server->on('handShake', array($this, 'onHandShake'));
        $this->server->on('workerStart', array($this, 'onWorkerStart'));
        $this->server->on('open', array($this, 'onOpen'));
        $this->server->on('message', array($this, 'onMessage'));
        $this->server->on('close', array($this, 'onClose'));

        $this->server->start();
    }

    public function onHandShake (\swoole_http_request $request, \swoole_http_response $response)
    {
        // 因为我需要在连接的时候校验信息,所以就自己处理握手了
        // 注意如果你要调用open,需要自行调用
        //........
    }

    public function onWorkerStart ($server, $worker_id)
    {
        # 载入框架入口文件
        require ROOT_PATH.'public/index.php';
        # 实例化业务逻辑类
        $this->application = new MatchApplication();
        if ($worker_id == 0) {

            $dir = app_path('Game/Match');
            $list[] = $dir;
            foreach (array_diff(scandir($dir), array('.', '..')) as $item) {
                $list[] = $dir.'/'.$item;
            }

            $notify = inotify_init();
            foreach ($list as $item) {
                inotify_add_watch($notify, $item, IN_CREATE | IN_DELETE | IN_MODIFY);
            }
            swoole_event_add($notify, function () use ($notify,$server) {
                $events = inotify_read($notify);
                if (!empty($events)) {
                    $server->reload();
                }
            });
        }
    }

    public function onOpen ($server, $request)
    {
        // 我的匹配是直接在onOpen做的,这里调用业务类的onOpen
        $this->application->onOpen($server,$request);
    }

    public function onClose ($server, $fd)
    {
        // 因为我这里使用了swoole_table来做进程间的数据交互,所以,当一个连接断开.我需要删除对应的数据
        if ($server->table->exist($fd)) {
            $server->table->del($fd);
        }
    }

检测是否能热更新成功

确保打印信息中没有你要热更新的代码

public function onWorkerStart ($server, $worker_id)
    {
        print_r(get_included_files());
        return;
        //......
    }

file

MatchApplication.php

public function onOpen ($server, $request)
{
    $fd = $request->fd;
    // 处理业务逻辑......
    $server->push($fd,$data);
    $server->close($fd);
}