前提:这里说的是典型的lnmp结构,nginx+php-fpm的模式
如果我有个php程序执行地非常慢,甚至于在代码中sleep(),然后浏览器连接上服务的时候,会启动一个php-fpm进程,但是这个时候,如果浏览器关闭了,那么请问,这个时候服务端的这个php-fpm进程是否还会继续运行呢?
今天就是要解决这个问题。
最简单的实验
最简单的方法就是做实验,我们写一个程序:在sleep之前和之后都用file_put_contents来写入日志:
<?phpfile_put_contents('/tmp/test.log', '11111' . PHP_EOL, FILE_APPEND | LOCK_EX);sleep(3);file_put_contents('/tmp/test.log', '2222' . PHP_EOL, FILE_APPEND | LOCK_EX);
实际操作的结果是,我们在服务器sleep的过程中,关闭客户端浏览器,2222是会被写入日志中。
那么就意味着浏览器关闭以后,服务端的php还是会继续运行的?
ignore_user_abort
老王和diogin提醒,这个可能是和php的ignore_user_abort函数相关。
于是我就把代码稍微改成这样的:
<?phpignore_user_abort(false);file_put_contents('/tmp/test.log', '11111' . PHP_EOL, FILE_APPEND | LOCK_EX);sleep(3);file_put_contents('/tmp/test.log', '2222' . PHP_EOL, FILE_APPEND | LOCK_EX);
发现并没有任何软用,不管设置ignore_user_abort为何值,都是会继续执行的。
但是这里有一个疑问: user_abort是什么?
文档对cli模式的abort说的很清楚,当php脚本执行的时候,用户终止了这个脚本的时候,就会触发abort了。然后脚本根据ignore_user_abort来判断是否要继续执行。
但是官方文档对cgi模式的abort并没有描述清楚。感觉即使客户端断开连接了,在cgi模式的php是不会收到abort的。
难道ignore_user_abort在cgi模式下是没有任何作用的?
是不是心跳问题呢?
首先想到的是不是心跳问题呢?我们断开浏览器客户端,等于在客户端没有close而断开了连接,服务端是需要等待tcp的keepalive到达时长之后才会检测出来的。
好,需要先排除浏览器设置的keepalive问题。
抛弃浏览器,简单写一个client程序:程序连接上http服务之后,发送一个header头,sleep1秒就主动close连接,而这个程序并没有带http的keepalive头。
程序如下:
package mainimport "net"import "fmt"import "time"func main() { conn, _ := net.Dial("tcp", "192.168.33.10:10011") fmt.Fprintf(conn, "GET /index.php HTTP/1.0/r/n/r/n") time.Sleep(1 * time.Second) conn.Close() return}
服务端程序:
<?phpignore_user_abort(false);file_put_contents('/tmp/test.log', '11111' . PHP_EOL, FILE_APPEND | LOCK_EX);sleep(3);file_put_contents('/tmp/test.log', '2222' . PHP_EOL, FILE_APPEND | LOCK_EX);
新闻热点
疑难解答