php使用register_shutdown_function或fastcgi_finish_request函数让代码返回数据后继续执行其它操作
最近遇到一个需求,异步请求对一个慢查询的结果进行缓存,先返回缓存的结果,然后继续获取数据缓存下来。写个demo记录下
使用register_shutdown_function函数
register_shutdown_function — 注册在关闭时执行的函数
注册一个 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();
数据立即返回,而耗时任务继续执行,满足预期。

日志:

浙公网安备 33010602011771号