php关闭浏览器继续执行踩坑记录

2023-06-03 11:43:59 浏览数 (1)

最近在项目中需要批量刷数据,但是由于项目的框架太老无法简单的使用命令行,而且项目比较急,所以想到之前的php关闭浏览器继续执行的路子,我记得php客户端断开继续执行需要配置nginx和fpm和php的配置,当时既修改php又修改fpm,但是找不到当时记录的配置信息了,后来想到自己之前测试过一个方法可行,于是翻出来了,代码如下:

代码语言:javascript复制
//设置客户端断开依然运行
ignore_user_abort(true);

//设置脚本不超时
set_time_limit(0);

//死循环每隔1秒访问一次网址
while (true)
{
    sleep(1);

    @file_get_contents('http://xingxinghan.cn/?id=5');
}

当时在windows下apache/nginx都测试过,linux下在本机测试过fpm和fast-cgi,于是直接用了上面的方法。

在测试环境和预发布环境都正常,但是到线上直接超时后脚本不再运行。害的产品和测试一直等我刷数据等到半夜。虽然我想到了fpm的配置项,但是当时脑子一片乱,没有想到。

也就是说上面的代码是在普通的cgi/fast-cgi下面是正常的,因为没有fpm的参与,脚本的执行时间受限于set_time_limit配置。

fpm环境中则由request_terminate_timeout配置时间决定,request_terminate_timeout 适用于当max_execution_time由于某种原因无法终止脚本的时候,会把这个php-fpm请求干掉。

但是还得找运维去修改配置的确麻烦,能不能自己在代码层参与。想了半天想到鸟哥科普的fastcgi_finish_request函数,这是一个fpm函数,开启了fpm才有。功能是提前向nginx响应请求,然后再去处理剩下的脚本代码。鸟哥文章原始链接https://www.laruence.com/2011/04/13/1991.html

于是我简单修改下代码,兼容下fpm的方法:

代码语言:javascript复制
function execute($func)
{
    $fpm_func = 'fastcgi_finish_request';
    if (function_exists($fpm_func))
    {
        //fpm
        fastcgi_finish_request();
    }
    else
    {
        //cgi/fast-cgi
        set_time_limit(0);
        ignore_user_abort(true);
    }
    $func();
}

测试代码如下:

代码语言:javascript复制
//执行任务内容
$func = function () {
    $pid = getmypid();
    $file = '1.txt';
    while (true)
    {
        $date = date('Y-m-d H:i:s');
        $text = "pid:{$pid},date:$date" . PHP_EOL;
        file_put_contents($file, $text);
        sleep(1);
    }
};

//正式执行任务
execute($func);

以上代码已经在win下apache/nginx的cgi/fast-cgi、linux下apache/nginx的cgi/fast-cgi/fpm下测试通过。phpenv集成环境中包含了fpm,貌似在windows中没看成有多大作用,fpm系列函数不可用,不过不影响执行。

切记!这是一个踩坑记录,不要偷懒,不要盲目自信,耗时的任务都走cli,如果要用这种方式最好加上日志记录,并且记录进程id,如果异常可以干掉相关进程,只限于刷数据,正式环境业务功能这么写就是猪!另外这种操作如果遇到不讲武德的web服务器,比如kangle/iis还可以不遵守这种规则,或者其他web服务器特殊配置超过就干掉你,也很无奈。

net5正式版发布了,推荐下还不错,优雅的c#语法、全面跨平台、原生二进制编译、更强的正则解析能力、保姆式开发工具人人都能简单入手。

php

0 人点赞