前言在实际项目中,经常会有这样的需求。对于前端发出的请求,需要在后端处理很长时间,但是为了让用户有更好的体验,为了让PHP在处理长期任务的时候不阻塞后端,快速响应页面请求,所以这里总结一下fastcgi_finish_request的应用。当然PHP实现非阻塞的方式有很多,比如异步脚本、swoole,但是个人认为fastcgi_finish_request是最简单方便的。基本应用fastcgi_finish_request介绍(PHP5>=5.3.3,PHP7)fastcgi_finish_request—将所有响应数据刷新(flush)到客户端booleanfastcgi_finish_request(void)该函数将所有响应数据刷新(flush)到客户端并结束请求。这允许长时间运行的任务在客户端结束连接后继续运行。返回值成功时返回TRUE,失败时返回FALSE。注意PHP和web服务器使用的是PHP-FPM(FastCGIProcessManager),那么可以通过fastcgi_finish_request()函数立即终止session,PHP线程可以继续在后台运行。也就是说这个功能只能用于php-fpm进程管理方式。只要代码运行到这个位置,就已经断开了请求,并将返回的参数发送给客户端。以下代码与客户端无关。也就是说页面上输出的内容必须放在fastcgi_finish_request函数之前。fastcgi_finish_request()结束客户端连接后,运行时间仍会受到max_execution_time超时的影响。也就是说,如果后端预计代码执行时间较长,还是需要设置set_time_limit(0)高并发下执行时间过长,也会造成fastcgi进程不足,如果不能及时释放,就会爆炸502错误。applicationecho"programstart...";file_put_contents('/tmp/garylog.log','start-time:'.date('Y-m-dH:i:s')."\n",FILE_APPEND);fastcgi_finish_request();sleep(1);//set_time_limit(0);//sleep(150);$num=25;$num+=1;sleep(5);echo'debug...';file_put_contents('/tmp/garylog.log','start-proceed:'.$num.',time'.date('Y-m-dH:i:s')."\n",FILE_APPEND);sleep(10);file_put_contents('/tmp/garylog.log','结束时间:'.date('Y-m-dH:i:s')."\n",FILE_APPEND);运行测试在代码可移植性上兼容非php-fpm,可以在代码中附上如下代码:if(!function_exists("fastcgi_finish_request")){functionfastcgi_finish_request(){}}代码部署在非fpm环境中。保证进程单一运行,可以解决上面提到的问题:如果高并发下执行时间过长,fastcgi进程会不够用,无法及时释放。同时,我们的需求只是起到触发作用,不需要每次都运行,所以可以考虑使用下面的方法,避免重复占用进程。$processId=realpath(__FILE__)。'-'.get_class($this);$filename=md5($processId);$file='/tmp/'.$filename;if(!file_exists($filename)){file_put_contents($file,getmypid());}else{返回真值;}##dosomethingCodethatneedstobeprocessedlongtime//处理完成后删除进程id记录文件unlink($file);参考PHP非阻塞实现方法
