php使用register_shutdown_function或fastcgi_finish_request函数让代码返回数据后继续执行其它操作

最近遇到一个需求,异步请求对一个慢查询的结果进行缓存,先返回缓存的结果,然后继续获取数据缓存下来。写个demo记录下

使用register_shutdown_function函数

register_shutdown_function — 注册在关闭时执行的函数

register_shutdown_function(callable $callbackmixed ...$args): void

注册一个 callback ,它会在脚本执行完成或者 exit() 后被调用。

<?php

class Test
{
    /**
     * 模拟长时间的工作
     */
    public function work($a, $b)
    {
        $this->writeLog(['working ...']);
        set_time_limit(0);
        sleep(4);
        $this->writeLog(['data:' . json_encode(compact('a', 'b'))]);
    }

    /**
     * 模拟返回json数据
     */
    function getJsonResponse()
    {
        ob_end_clean();
        header("Connection: close");
        header("HTTP/1.1 200 OK");
        header("Content-Type: application/json;charset=utf-8");
        ob_start();
        echo json_encode(['a' => 1]);
        $size = ob_get_length();
        header("Content-Length: $size");
        ob_end_flush();
        flush();
    }

    /**
     * 测试使用 register_shutdown_function
     */
    public function test1()
    {
        $this->getJsonResponse();

        $this->writeLog(['register_shutdown_function begin ...']);
        register_shutdown_function([$this, 'work'], 2, 3);
        $this->writeLog(['register_shutdown_function end ...']);
    }

    /**
     * 记录日志
     */
    function writeLog(array $params): void
    {
        $msg = array_pop($params);
        array_unshift($params, date('Y-m-d H:i:s'));
        $params = array_map(function ($val) {
            return  '[' . $val . ']';
        }, $params);
        array_push($params, $msg);
        $msg = array_reduce($params, function ($carry, $val) use ($params) {
            return  $carry . $val;
        }, '');
        file_put_contents('./files/test.log', $msg . "\r\n", FILE_APPEND);
    }
}

$t = new Test();
$res = $t->test1();

数据立即返回,而耗时任务继续执行,满足预期。

日志:

使用fastcgi_finish_request函数

fastcgi_finish_request(): bool

此函数冲刷(flush)所有响应的数据给客户端并结束请求。这允许在不打开与客户端之间的连接的情况下执行耗时任务。

<?php

class Test
{
    /**
     * 模拟长时间的工作
     */
    public function work($a, $b)
    {
        $this->writeLog(['working ...']);
        set_time_limit(0);
        sleep(4);
        $this->writeLog(['data:' . json_encode(compact('a', 'b'))]);
    }

    /**
     * 模拟返回json数据
     */
    function getJsonResponse()
    {
        ob_end_clean();
        header("Connection: close");
        header("HTTP/1.1 200 OK");
        header("Content-Type: application/json;charset=utf-8");
        ob_start();
        echo json_encode(['a' => 1]);
        $size = ob_get_length();
        header("Content-Length: $size");
        ob_end_flush();
        flush();
    }

    /**
     * 测试使用 fastcgi_finish_request
     */
    public function test2()
    {
        $this->getJsonResponse();

        $this->writeLog(['fastcgi_finish_request begin ...']);
        if (function_exists("fastcgi_finish_request")) {
            fastcgi_finish_request();
        }
        $this->work(2, 3);
        $this->writeLog(['fastcgi_finish_request end ...']);
    }



    /**
     * 记录日志
     */
    function writeLog(array $params): void
    {
        $msg = array_pop($params);
        array_unshift($params, date('Y-m-d H:i:s'));
        $params = array_map(function ($val) {
            return  '[' . $val . ']';
        }, $params);
        array_push($params, $msg);
        $msg = array_reduce($params, function ($carry, $val) use ($params) {
            return  $carry . $val;
        }, '');
        file_put_contents('./files/test.log', $msg . "\r\n", FILE_APPEND);
    }
}

$t = new Test();
$res2 = $t->test2();

数据立即返回,而耗时任务继续执行,满足预期。

日志:

 

posted @ 2024-06-14 11:40  carol2014  阅读(293)  评论(0)    收藏  举报