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 的事件顺序

时间: 2024-08-29 20:05:58

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

回调函数中调用类中的非静态成员变量或非静态成员函数

有关这方面的问题,首先说一点: 回调函数必须是静态成员函数或者全局函数来实现回调函数,大概原因是普通的C++成员函数都隐含了一个函数参数,即this指针,C++通过传递this指针给成员函数从而实现函数可以访问类的特定对象的数据成员.由于this指针的原因,使得一个普通成员函数作为回调函数时就会因为隐含的this指针问题使得函数参数个数不匹配,从而导致回调函数编译失败. 基于上面的理论,如何在类中封装回调函数呢? 回调函数只能是全局函数或者静态成员函数,但是由于全局函数会破坏封装性,所以只能用静

ajax回调函数中使用$(this)取不到对象的解决方法

如果在ajax的回调函数内使用$(this)的话,实践证明,是取不到任何对象的,需要的朋友可以参考下 $(".derek").each(function(){ $(this).click(function(){ var params = $(this).parent().serialize(); var obj=$(this).parent().siblings("div#caskContent"); var form=$(this).parent(); $.aja

理解 JS 回调函数中的 this

理解 JS 回调函数中的 this:https://www.cnblogs.com/gavinyyb/p/6286750.html 原文链接:http://www.tuicool.com/articles/z2Yvaq 任何变量或对象都有其赖以生存的上下文.如果简单地将对象理解为一段代码,那么对象处在不同的上下文,这段代码也会执行出不同的结果. 例如,我们定义一个函数 getUrl 和一个对象 pseudoWindow . function getUrl() { console.log(this

wx: wx.showModal 回调函数中调用自定义方法

一.在回调函数中调用自定义方法: 回调函数中不能直接使用this,需要在外面定义 var that = this 然后 that.自定义的方法.如下: //删除 onDelete: function (e) { var that = this; wx.showModal({ title: '提示', content: '确定要删除?', success: function (res) { if (res.confirm) { that.onEdit(e); } } }) }, //编辑 onEd

vue中this在回调函数中的使用

this在各类回调中使用: 如果是普通函数是没法使用的 所以需要先将this.变量赋值给新的变量,然后才能在回调函数中使用 例如: refund: function (id) { if (!this.url.refund) { this.$message.error("请设置url.refund属性!") return } var that = this; this.$confirm({ title: "确认退款", content: "是否要进行退款?&

hiredis aeStop仅在redis命令的回调函数中生效 分析

hiredis 是 redis 的client端C语言 lib,  hiredis拥有同步和异步的API, 异步API的实现有多种方法,分别依赖libev, libevent, libuv, ae等等,其中ae是redis内部实现的一个异步事件处理模块. 稍微修改了hiredis的example-ae.c代码:在一个线程里面循环10次执行命令ping, 检查redisserver, 如下所示, 线程发完10次ping后,调用disconnect, 发现aeMain函数并未退出,程序一直阻塞住.

前端小组分享会之异步回调函数中的上下文

异步加载:又叫非阻塞加载,浏览器在下载执行js的同时,还会继续进行后续页面的处理.实现如:回调函数 .setTimeout . setInterval  回调函数(callback): 自己理解就是函数A里嵌套函数B B可能用到A中的变量,,B成为回调函数 function a (){ var x = 1; function b(){ console.log(++x) } b() } a() //2 上下文(Execution Context): 执行上下文(简称上下文)决定了Js执行过程中可以

=&gt; 应用在js回调函数中

=> 可以简化以前的回调函数的调用,具体来说: 今后,几乎所有的回调函数都可用箭头函数简化 比如: 1. 所有回调函数都可: 去function改=> 2. 如果函数体只有一句话: 可省略{} 如果这一句话还是return,可省略return 3. 如果只有一个参数: 可省略() 但是,如果没有参数,必须保留空() 更大用途: 箭头函数内外共用同一个this--取代bind 特殊: 如果不希望内外共用this,就不能用箭头函数 比如事件处理函数: elem.addEventListener(&

观察者模式在One Order回调函数中的应用

例如需求是搞清楚function module CRM_PRODUCT_I_A_CHANGE_ORGM_EC在什么样的场景下会被调用.当然最费时间的做法是设一个断点,然后跑对应的场景,观察断点何时被触发.也有另一种不通过调试的分析方法: 使用事务码CRMV_EVENT, 输入函数名称CRM_PRODUCT_I_A_CHANGE_ORGM_EC: 得到结果: 上述结果的业务含义是:每当Sales area被创建或者更新时,我们查询的function module都会自动被One Order框架调用