Yii2控制器使用pcntl_fork后redirect重定向延迟问题求解
问题根因
该重定向延迟是两个核心原因共同导致的:
- 子进程默认继承了当前请求的所有文件描述符(包括和Web服务器通信的IO句柄),Web服务器会等待所有持有该句柄的进程退出后,才会将响应内容发送给客户端
- 未对子进程进行脱离处理,父进程退出后子进程会变成僵尸进程持续占用资源,也会阻塞响应输出
解决代码修改方案
你需要在子进程逻辑分支添加进程脱离、继承资源释放的处理,同时在父进程侧注册信号处理忽略子进程退出信号,避免父进程等待子进程回收。修改后的代码如下:
// 控制器方法最开头注册信号处理,忽略子进程退出信号,父进程无需等待回收子进程 pcntl_signal(SIGCHLD, SIG_IGN); //Start timer marker for($i=0;$i<5;$i++) { sleep(1); $pid = pcntl_fork(); if(!$pid) { //Child Process 核心修改部分 // 1. 创建新会话,让子进程脱离父进程的进程组控制,成为独立守护进程 posix_setsid(); // 2. 关闭继承自父进程的所有标准IO流,释放和Web服务器通信的句柄 fclose(STDIN); fclose(STDOUT); fclose(STDERR); // 3. 关闭继承自父进程的数据库、session等资源,避免和父进程共用连接导致冲突 Yii::$app->db->close(); Yii::$app->session->close(); sleep(30); //Child process Timer marker 30 seconds //processing as expected // 子进程执行完逻辑后直接退出,不要走父进程后续的控制器逻辑 exit(0); } else if ($pid == -1) { // 进程创建失败错误处理 throw new \Exception('异步进程创建失败'); } else { //PARENT //Parent timer marker loops 5x 1xloop seconds } } //Redirect Timer marker at 5 seconds return $this->redirect(['/account/account-details','accountId'=>Yii::$app->session['accountId']]);
额外注意点
- 不要在子进程里直接操作父进程的请求上下文、共用数据库/缓存连接等资源,如子进程需要使用相关资源,建议在子进程内重新初始化
- 该方案仅适用于CLI或者进程隔离的FPM模式,Swoole/Workerman等常驻内存框架不要在请求处理逻辑中直接使用
pcntl_fork - 如果异步逻辑执行时间长、调用频率高,更建议改用队列服务处理异步任务,不要在请求控制器中直接fork进程,避免服务器进程溢出
内容的提问来源于stack exchange,提问作者Scott Johnson
相关产品推荐
相关产品推荐

