首页 > 代码库 > Swoole 关于reload重启与回调函数中代码的重载

Swoole 关于reload重启与回调函数中代码的重载

Swoole 的 Server 中可以通过 PHP 来执行 reload 很方便的热重载, 但也有很多限制

需要注意的是, 直接写在 server.php 即 你的服务器启动脚本文件中的PHP代码即便是写在 WorkerStart 的事件回调中的代码 reload 也不会重载的, 必须是通过加载另一个文件来执行这样 reload 才会有意义

下面是测试代码和结果说明:

<?php
/**
 * Author: ZHOUZ
 * Blog: http://blog.csdn.net/zhouzme
 * Time: 2017-04-05 15:22
 */
function server()
{
    $server = new Swoole\Http\Server("0.0.0.0", 9501);

    /**
     * 测试在 $server 外部注册全局自定义属性, 看看会不会被覆盖
     */

    $server->myWorkerVar = ‘global‘;

    $server->set(array(
        ‘worker_num‘ => 2,
        ‘daemonize‘ => false,
    ));

    // 服务器启动时执行一次
    $server->on(‘Start‘, function (\Swoole\Http\Server $server) {
        echo PHP_EOL . PHP_EOL . ‘Start: http://blog.csdn.net/zhouzme‘ . PHP_EOL . PHP_EOL;
    });

    // 服务器启动时执行一次
    $server->on(‘ManagerStart‘, function (\Swoole\Http\Server $server) {
        echo ‘ManagerStart: ‘ . PHP_EOL . PHP_EOL;
    });

    // 每个 Worker 进程启动或重启时都会执行
    $server->on(‘WorkerStart‘, function (\Swoole\Http\Server $server, int $workerId) {
        // 通过重新加载外部文件来重载代码和释放之前占用的内存
        //include_once __DIR__ . DIRECTORY_SEPARATOR .‘workerstart.php‘;
        // 下面这些直接写在当前文件中的代码即便重载也不会变化

        echo ‘WorkerStart: ‘ . PHP_EOL . PHP_EOL;
        echo ‘    Worker ID: ‘ . $workerId . PHP_EOL . PHP_EOL;
        // 启动服务器后, 去掉下面这行注释, 然后 reload , 该语句也不会执行的
        //echo ‘        reloaded ! ‘ . PHP_EOL . PHP_EOL;
        // 应该把这里的回调事件代码写在另一个文件中来 include 而不是直接写在这里
        // 注意即便是 include_once , reload 也会重新加载的, 但在你的逻辑控制中是有效的
    });

    // 每次连接时(相当于每个浏览器第一次打开页面时)执行一次, reload 时连接不会断开, 也就不会再次触发该事件
    $server->on(‘Connect‘, function (\Swoole\Http\Server $server, int $fd, int $reactorThreadId) {
        echo ‘Connect: ‘ . PHP_EOL . PHP_EOL;
        echo ‘    Worker ID: ‘. $server->worker_id . PHP_EOL . PHP_EOL;
        echo ‘        fd: ‘ . $fd . ‘ , fromId: ‘ . $reactorThreadId . PHP_EOL . PHP_EOL;
    });

    // 浏览器连接服务器后, 页面上的每个请求均会执行一次,
    // 每次打开链接页面默认都是接收两个请求, 一个是正常的数据请求, 一个 favicon.ico 的请求
    $server->on(‘Request‘, function (\Swoole\Http\Request $request, \Swoole\Http\Response $response) use ($server) {

        // 通过加载文件的方式来重载代码, 如果是 include_once 则只有第一次请求会加载, 其中的代码也只有第一次请求才会执行
        include_once __DIR__ . DIRECTORY_SEPARATOR .‘workerrequest.php‘;
        // 下面所有的代码都应该放到另一个文件中, 否则 reload 无效, 你就只能 shutdown 再 start 了

        // 下面这行去掉注释后 reload 也不会输出的
        //echo ‘        ~~~~~ request reloaded ~~~~~ !‘;

        if ($request->server[‘request_uri‘] == ‘/favicon.ico‘) {
            $response->end();
            return;
        }

        echo ‘Request: ‘ . PHP_EOL . PHP_EOL;
        echo ‘    Worker ID: ‘. $server->worker_id . PHP_EOL . PHP_EOL;
        echo ‘    URL: ‘ . ($request->server[‘request_uri‘] ?? ‘‘) . PHP_EOL . PHP_EOL;

        // 通过链接参数热重载 worker 进程观察触发事件
        $act = $request->get[‘act‘] ?? ‘‘;
        if ($act == ‘reload‘) {
            echo ‘    ... Swoole Reloading ! ... ‘ . PHP_EOL . PHP_EOL;

            // 触发 reload 之后, 貌似后面的代码也还是会执行的
            $server->reload();
            echo ‘    ... Under Reload ! ... ‘ . PHP_EOL . PHP_EOL; // 看看 reload 时是否会执行后续的代码
        } elseif ($act == ‘exit‘) {
            // 直接立即终止当前 worker 进程, 和 reload 的效果比较相似, 新的 worker 进程的 ID 和原来的一样
            // 所以程序内部应该尽量避免使用 exit 而应该抛出异常在外部 catch
            echo ‘    ... Swoole Exit ! ... ‘ . PHP_EOL . PHP_EOL;
            exit;
        } elseif ($act == ‘shutdown‘) {
            // 直接立即终止当前 worker 进程, 和 reload 的效果比较相似, 新的 worker 进程的 ID 和原来的一样
            // 所以程序内部应该尽量避免使用 exit 而应该抛出异常在外部 catch
            echo ‘    ... Swoole Shutdown ! ... ‘ . PHP_EOL . PHP_EOL;
            $server->shutdown();
            echo ‘    ... After Swoole Shutdown ! ... ‘ . PHP_EOL . PHP_EOL;
        }

        $response->header("X-Server", "Swoole");
        $msg = ‘hello swoole !‘;
        $response->end($msg);
    });

    $server->start();
}

server();

所有回调事件中的代码逻辑应该写在另一个文件中通过 include 来加载, 这样 reload 时才能平滑重启, 否则只能 shutdown server 再 start 了

WorkerStart 中 include 和 include_once 应该是没有区别的

Request 中 include_once 则只有第一次请求会加载并执行其中的代码, 之后的请求则会忽略加载也不会执行了, 但 reload 之后会重新加载文件并执行其中的代码

测试代码的输出结果:

技术分享

技术分享

技术分享

技术分享

Swoole 相关其他文章

Swoole 关于变量作用域的问题

Swoole 关于 HTTP SERVER 的事件顺序

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    Swoole 关于reload重启与回调函数中代码的重载